Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: payment component #106

Merged
merged 24 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5964f02
fix: do not change route while connecting
rolznz Nov 10, 2023
4a0b745
feat: improve error message display
rolznz Nov 10, 2023
8c3ee99
feat: payment component WIP
rolznz Nov 11, 2023
f61fc9c
feat: send payment page WIP
rolznz Nov 15, 2023
e9a7df9
fix: invoice decoding and success image
rolznz Nov 18, 2023
c5a5d26
feat: expose bitcoin connect API
rolznz Nov 18, 2023
7a57b66
chore: move bc-send-payment to pages folder
rolznz Nov 18, 2023
01aa69d
chore: remove comment
rolznz Nov 18, 2023
da7ba5e
fix: success screen, automatically close modal
rolznz Nov 18, 2023
3f82b49
feat: add disconnect, isConnected API methods
rolznz Nov 18, 2023
73eb0c8
fix: do not request balance when invoice exists
rolznz Nov 20, 2023
2e237c4
feat: payment request modal title, switch connector workaround on pay…
rolznz Nov 20, 2023
fae2837
feat: common disconnect section, copy invoice, minor styling changes
rolznz Nov 20, 2023
759dae3
feat: use qr code library
rolznz Nov 20, 2023
feb35c0
fix: update website link
rolznz Nov 20, 2023
460ddfe
feat: payment request mobile view
rolznz Nov 20, 2023
a5db44f
chore: undo unnecessary changes
rolznz Nov 20, 2023
2c3e461
chore: remove old comment
rolznz Nov 20, 2023
a7453fa
chore: minor UI and copy tweaks
rolznz Nov 22, 2023
0672fda
fix: qr code size and dark mode hr color
rolznz Nov 22, 2023
3d55079
fix: font on error message
rolznz Nov 22, 2023
c7410f9
fix: spacing & font
reneaaron Nov 22, 2023
61b21e1
fix: remove unnecessary as const
rolznz Nov 22, 2023
d4c211d
Merge branch 'feat/payment-component' of github.com:getAlby/bitcoin-c…
rolznz Nov 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

This project includes web components for connecting to Lightning wallets and enabling [WebLN](https://webln.guide). Websites only need to implement a single interface to connect with multiple wallets (WebLN), and users can connect from both desktop and mobile devices. These components work with pure HTML and all Javascript libraries or frameworks, such as React, Angular, Vue, Solid.js, etc.

🆕 Bitcoin Connect also supports a nice invoice payment UI that gives a multitude of options to a user to pay an invoice. Accept payments with a single line of code.

## 🛝 Try it out here

<h1>
Expand Down Expand Up @@ -37,7 +39,7 @@ You can use Bitcoin Connect without any build tools:
### React

```jsx
import {Button, Modal, launchModal} from '@getalby/bitcoin-connect-react';
import {Button, Modal, launchModal, closeModal} from '@getalby/bitcoin-connect-react';

// render a button
<Button onConnect={() => alert('Connected!')} />
Expand All @@ -48,6 +50,14 @@ import {Button, Modal, launchModal} from '@getalby/bitcoin-connect-react';
<button onClick={launchModal}>
Programmatically launch modal
</button>

// open modal programmatically to pay an invoice
<button onClick={() => launchModal({invoice: "lnbc...."})}>
Programmatically launch modal
</button>

// close modal programmatically
closeModal();
```

#### React SSR / NextJS
Expand All @@ -69,6 +79,9 @@ Bitcoin Connect exposes the following web components for allowing users to conne
- Optional Arguments:
- `open` - make the modal appear
- `<bc-connector-list/>` - render the list of connectors on their own
- `<bc-send-payment/>` - render a payment request UI
- Arguments:
- `invoice` - BOLT11 invoice
- _more components coming soon_

##### Common Attributes (can be passed to any Bitcoin Connect component)
Expand All @@ -86,11 +99,37 @@ Bitcoin Connect exposes the following events:
- `bc:modalopened` window event which fires when Bitcoin Connect modal is opened
- `bc:modalclosed` window event which fires when Bitcoin Connect modal is closed

### Bitcoin Connect API

#### Programmatically launching the modal

`<bc-modal/>` needs to be rendered somewhere on the page. The modal can then be launched with:

`document.querySelector('bc-modal').setAttribute('open', true)`
```js
window.bitcoinConnect.launchModal();
```

`launchModal` can also take an optional options object:

```js
launchModal({
invoice: 'lnbc...', // bolt11 invoice
});
```

#### Programmatically closing the modal

`window.bitcoinConnect.closeModal();`

#### Disconnect from wallet

`window.bitcoinConnect.disconnect();`

#### Check connection status

`window.bitcoinConnect.isConnected();`

_More methods coming soon. Is something missing that you'd need? let us know!_

### Styling

Expand Down Expand Up @@ -230,6 +269,10 @@ You should have a certain level of trust on the website you decide to connect yo
- [Mutiny NWC URL](https://www.mutinywallet.com/)
- [Generic NWC URL](https://github.com/nostr-protocol/nips/blob/master/47.md)

### If a user pays with another wallet why does the modal stay open?

Bitcoin Connect cannot detect payments made externally. It's up to your app to detect the payment and then programmatically close the modal using the exposed `closeModal` function.

## Known Issues

- NWC connectors do not work on iOS in non-secure contexts because window.crypto.subtle is unavailable. If testing on your phone, please run an https server or use an https tunnel.
Expand Down
2 changes: 1 addition & 1 deletion demos/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@getalby/bitcoin-connect-react": "^2.3.1",
"@getalby/bitcoin-connect-react": "2.4.0-alpha.3",
"@getalby/lightning-tools": "^4.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
7 changes: 7 additions & 0 deletions demos/react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ function App() {
<button style={{marginTop: '16px'}} onClick={launchModal}>
Programmatically launch modal
</button>
<br />
<button
style={{marginTop: '16px'}}
onClick={() => launchModal({invoice})}
>
Programmatically launch modal to pay invoice
</button>
</>
);
}
Expand Down
37 changes: 23 additions & 14 deletions demos/react/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -149,19 +149,20 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.46.0.tgz#3f7802972e8b6fe3f88ed1aabc74ec596c456db6"
integrity sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==

"@getalby/bitcoin-connect-react@^2.3.1":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@getalby/bitcoin-connect-react/-/bitcoin-connect-react-2.3.1.tgz#2bf4171a48e631ae79bd90465c38cb793b551fd5"
integrity sha512-SSWAtCpxvEbFIiHvJ6IFZOgUd4zW3HUz5AvbQ3B/L1PBLR8d7NZQ8vXNQKh99Ez5zuCwbPHQwEFzNbNUSOpZoQ==
"@getalby/bitcoin-connect-react@2.4.0-alpha.3":
version "2.4.0-alpha.3"
resolved "https://registry.yarnpkg.com/@getalby/bitcoin-connect-react/-/bitcoin-connect-react-2.4.0-alpha.3.tgz#a1c2632fbbea1872f4026511a36c2e32d4afe7de"
integrity sha512-XFPcsyE8XeC7SJaQB6/TEVqRts3exa54CqYGnzHeZQZS0UGkGqDQjvX2GIxQpLCXwe85UOhSYrPCi2i2FKuwfw==
dependencies:
"@getalby/bitcoin-connect" "^2.3.1"
"@getalby/bitcoin-connect" "2.4.0-alpha.3"

"@getalby/bitcoin-connect@^2.3.1":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@getalby/bitcoin-connect/-/bitcoin-connect-2.3.1.tgz#74c259b52f0ecc4bebe59c26171921006c3c62a1"
integrity sha512-fZXLFMAKBpYJHq0roh+KaB4vUIIqahK8KxV+nqJWJdGL/ge5CqYFb3LR685gj/4AquzDrqeWtRW53uKBFMgXXQ==
"@getalby/bitcoin-connect@2.4.0-alpha.3":
version "2.4.0-alpha.3"
resolved "https://registry.yarnpkg.com/@getalby/bitcoin-connect/-/bitcoin-connect-2.4.0-alpha.3.tgz#a7860e2ebb71f277c74ac23efef705b8d79593b5"
integrity sha512-FlOT6sVWJ/oSDssZFa/Vao4eLzgJOEXWODl2IJrlb76jqhaNvkqk4Iv7a4kY/1kWcYbU6MLeR+bargeKlZvxFw==
dependencies:
"@getalby/sdk" "^2.4.0"
"@getalby/lightning-tools" "^4.2.0"
"@getalby/sdk" "^2.6.0"
"@lightninglabs/lnc-web" "^0.2.6-alpha"
lit "^3.0.0"
zustand "^4.4.1"
Expand All @@ -174,10 +175,18 @@
crypto-js "^4.1.1"
light-bolt11-decoder "^3.0.0"

"@getalby/sdk@^2.4.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@getalby/sdk/-/sdk-2.5.0.tgz#d1b0a22cbcf986755c4b684096d97f52ed0b469d"
integrity sha512-MRLgI6WxCCLgrar+qDqm/UhKs+V6yXzNm4y1bJRAuN72nkKT+TjTJHCmk9GjTngR3FrOfLbeMsPwBxCmbvfrLQ==
"@getalby/lightning-tools@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@getalby/lightning-tools/-/lightning-tools-4.2.0.tgz#768025e7efb2e8c0271859ed7956615c83b73b76"
integrity sha512-o87OTIgKgzOjDPoepDATQVGc2WkrO0Mwt4w+QAorYJx1z5MaCTipJi2cTO0GESObH1sEWCorZikanhMoRUh+qA==
dependencies:
crypto-js "^4.1.1"
light-bolt11-decoder "^3.0.0"

"@getalby/sdk@^2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@getalby/sdk/-/sdk-2.6.0.tgz#51508c7833b0580575055f15b8fe21567b76288a"
integrity sha512-klD1FrpGY39QldPf00KtzIveWj0dXtgGdZH6nLWdJ0Ness7FAqy2RkgSF7JQfKJeJSFek7Ip3AL/KCT5/lZgww==
dependencies:
crypto-js "^4.1.1"
events "^3.3.0"
Expand Down
48 changes: 43 additions & 5 deletions dev/vite/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,21 @@
alert('Failed to pay: ' + error);
}
}
(async () => {
const ln = new window.lightningTools.LightningAddress(
'[email protected]'
);
await ln.fetch();
const invoice = await ln.requestInvoice({satoshi: 1});
document
.getElementsByTagName('bc-send-payment')[0]
.setAttribute('invoice', invoice.paymentRequest);
})();
</script>
<style>
body {
font-family: Arial, Helvetica, sans-serif;
margin: 0px;
@media (prefers-color-scheme: dark) {
background-color: black;
color: white;
Expand Down Expand Up @@ -93,12 +104,13 @@
</head>
<body>
<h1>Programmatic Access</h1>
<button onclick="window.bitcoinConnect.launchModal()">Open modal</button>
<button
onclick="document.querySelector('bc-modal').setAttribute('open', true)"
onclick="const invoiceToPay = window.prompt('paste invoice'); window.bitcoinConnect.launchModal({invoice: invoiceToPay})"
>
Open modal
Open modal to pay invoice
</button>
<bc-modal></bc-modal>
<bc-modal id="first-modal"></bc-modal>

<br /><br />
<a href="balance.html">Balance tester</a>
Expand Down Expand Up @@ -135,6 +147,11 @@ <h1>Settings</h1>
id="filters"
onchange="localStorage.setItem('filters', document.getElementById('filters').value); window.location.reload()"
/>
<p>Invoice</p>
<input
id="invoice"
onchange="localStorage.setItem('invoice', document.getElementById('invoice').value); window.location.reload()"
/>
<br />
<br />
<h1>Components</h1>
Expand Down Expand Up @@ -174,6 +191,13 @@ <h2>Router outlet</h2>
<bc-router-outlet></bc-router-outlet>
</div>

<h2>Request Payment Screen</h2>
<div style="width: 448px; border: 1px solid black">
<bc-send-payment
invoice="lnbc10n1pj4g7ugpp5h0lld9qzh06ngn8ur756rva0ntfdfg34h298337rljjyztxy8rfqhp50kncf9zk35xg4lxewt4974ry6mudygsztsz8qn3ar8pn3mtpe50scqzzsxqyz5vqsp5lwlnu7xjs7hj7vltx7rhzsjf60l5mwckuw93qngjrz7sdhdkw7gs9qyyssqzy543rxhkdtncjrmuzlz4lrh2eauldawa9np5yysh7dhqhv8kaahydurha2cfelr7t6wt33xse7fdykupnjv36na6x6crrhy53lyg6cqf2jhjj"
></bc-send-payment>
</div>

<h2>Start screen</h2>
<div style="width: 448px">
<bc-start></bc-start>
Expand All @@ -196,11 +220,25 @@ <h2>Pay an invoice</h2>
<script>
const appName = localStorage.getItem('app-name');
document.getElementById('app-name').value = appName;
document.getElementById('first-button').setAttribute('app-name', appName);
if (appName) {
document
.getElementById('first-button')
.setAttribute('app-name', appName);
}

const filters = localStorage.getItem('filters');
document.getElementById('filters').value = filters;
document.getElementById('first-button').setAttribute('filters', filters);
if (filters) {
document
.getElementById('first-button')
.setAttribute('filters', filters);
}

const invoice = localStorage.getItem('invoice');
document.getElementById('invoice').value = invoice;
if (invoice) {
document.getElementById('first-modal').setAttribute('invoice', invoice);
}
</script>
</body>
</html>
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@getalby/bitcoin-connect",
"version": "2.3.1",
"version": "2.4.0-alpha.7",
"description": "Web components to connect to a lightning wallet and power a website with WebLN",
"type": "module",
"source": "src/index.ts",
Expand Down Expand Up @@ -45,9 +45,10 @@
"author": "Alby",
"license": "MIT",
"dependencies": {
"@getalby/sdk": "^2.4.0",
"@getalby/lightning-tools": "^4.2.0",
"@getalby/sdk": "^2.6.0",
"@lightninglabs/lnc-web": "^0.2.6-alpha",
"lit": "^3.0.0",
"qrcode-generator": "^1.4.4",
"zustand": "^4.4.1"
},
"devDependencies": {
Expand All @@ -65,6 +66,7 @@
"concurrently": "^8.2.0",
"esbuild": "^0.18.17",
"eslint": "^8.15.0",
"lit": "^3.0.0",
"lit-analyzer": "^1.2.1",
"microbundle": "^0.15.1",
"prettier": "^2.6.2",
Expand Down
4 changes: 2 additions & 2 deletions react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@getalby/bitcoin-connect-react",
"version": "2.3.1",
"version": "2.4.0-alpha.7",
"type": "module",
"source": "src/index.ts",
"main": "./dist/index.cjs",
Expand All @@ -21,7 +21,7 @@
"build": "microbundle --globals react=React --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react"
},
"dependencies": {
"@getalby/bitcoin-connect": "^2.3.1"
"@getalby/bitcoin-connect": "2.4.0-alpha.7"
},
"devDependencies": {
"@types/react": "^18.2.21",
Expand Down
11 changes: 0 additions & 11 deletions react/src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,3 @@ export const Modal: React.FC<ModalProps> = (props) => {
// @ts-ignore
return <bc-modal app-name={props.appName} filters={props.filters} />;
};

// TODO: move to bitcoin connect package and just re-export it here
export function launchModal() {
const modal = document.querySelector('bc-modal');
if (!modal) {
throw new Error(
'bc-modal does not exist in the dom. Did you render the Modal somewhere on this page?'
);
}
modal.setAttribute('open', 'true');
}
8 changes: 8 additions & 0 deletions react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
export * from './components/Button';
export * from './components/Modal';
import {
closeModal,
disconnect,
isConnected,
launchModal,
} from '@getalby/bitcoin-connect';

export {launchModal, closeModal, disconnect, isConnected};
Loading