Skip to content

Commit

Permalink
feat: extend webln in alby
Browse files Browse the repository at this point in the history
  • Loading branch information
pavanjoshi914 committed Apr 16, 2022
1 parent 3e69e7e commit ed6f755
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 7 deletions.
27 changes: 27 additions & 0 deletions src/app/components/PaymentSummary.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.details-img {

position: relative;
width: 40%;
margin: 0 auto;

}
.details-img img{
display: block;
margin: 50px auto;
width: 100%;
max-width: 250px;
border-radius: 50%;
box-shadow: 6px 6px 12px rgba(0, 0, 0, 0.8), -6px -6px 12px rgba(255, 255, 255, 0.4);
}

.details-img:after {
content: '';
display: block;
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
border-radius: 50%;
border: 3px dashed rgba(255, 206, 0, 1);
}
57 changes: 56 additions & 1 deletion src/app/components/PaymentSummary.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,57 @@
import React from 'react';
import './PaymentSummary.css';
type Props = {
amount: string | React.ReactNode;
amountAlt?: string;
description?: string | React.ReactNode;
metadata?: string;
};

function PaymentSummary({ amount, amountAlt, description }: Props) {


function PaymentSummary({ amount, amountAlt, description, metadata }: Props) {

function formattedMetadata(
metadataJSON: string
): [string, string | React.ReactNode][] {
try {
// if json array passed, formats that json array into simple array and returns the metadata which can be rendered on screen effectively
const metadata = JSON.parse(metadataJSON);
// console.log(metadata);

return metadata
.map(([type, content]: [string, string]) => {

return [type, content];


})
.filter(Boolean);
} catch (e) {
console.error(e);
}
return [];
}


const metadataRender =formattedMetadata(metadata!).map(([dt, dd]) => {

if(dt === "image"){
const imageUrl = `data:image/jpeg;base64,${dd}`
return <>
<dt>{dt}</dt>
<dd><div className="details-img"><img src={imageUrl}/></div></dd>

</>
}
else
return <>
<dt>{dt}</dt>
<dd>{dd}</dd>

</>
})

return (
<div className="p-4 shadow bg-white border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600">
<dl className="mb-0">
Expand All @@ -17,6 +64,14 @@ function PaymentSummary({ amount, amountAlt, description }: Props) {
Description
</dt>
<dd className="mb-0 dark:text-white">{description}</dd>
<dt className="mt-4 uppercase font-semibold text-gray-500 text-xs">
Metadata
</dt>
{metadataRender}

{console.log(metadata)}


</dl>
</div>
);
Expand Down
10 changes: 10 additions & 0 deletions src/app/components/TransactionsTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import { Transaction } from "../../../types";
import Badge from "../Badge";

type Props = {
// varible transactions hold the list of the type Transaction
transactions: Transaction[];
};


// loads transactions done to the given websites
export default function TransactionsTable({ transactions }: Props) {
function renderIcon(type: string) {
function getIcon() {
Expand All @@ -33,6 +36,8 @@ export default function TransactionsTable({ transactions }: Props) {
);
}

// transactions contains all the transactions present in array of type Transaction i.e Transaction[]
console.log(transactions);
return (
<div className="shadow overflow-hidden rounded-lg">
<div className="bg-white divide-y divide-gray-200 dark:bg-gray-700">
Expand Down Expand Up @@ -85,6 +90,7 @@ export default function TransactionsTable({ transactions }: Props) {
<Disclosure.Panel>
<div className="mt-1 ml-9 text-xs text-gray-500 dark:text-gray-400">
{tx.description}

{tx.preimage && (
<p className="truncate">Preimage: {tx.preimage}</p>
)}
Expand All @@ -95,6 +101,10 @@ export default function TransactionsTable({ transactions }: Props) {
) : (
""
)}

{ (
<p className="truncate">Metadata: {tx.metadata}</p>
)}
</div>
</Disclosure.Panel>
</>
Expand Down
4 changes: 4 additions & 0 deletions src/app/router/Prompt/Prompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Prompt extends Component<
super(props);
const message = qs.parse(window.location.search);
let origin = {} as OriginData;
// metadata and paymentRequest lnbc string passed via SendPayment is stored in args object
let args = {};
let type = "";
if (message.origin && typeof message.origin === "string") {
Expand Down Expand Up @@ -98,6 +99,9 @@ class Prompt extends Component<
<ConfirmPayment
paymentRequest={this.state.args?.paymentRequest as string}
origin={this.state.origin}
// arguments of the states contain paymentRequest and metadata paramter

metadata ={this.state.args?.metadata as string}
/>
}
/>
Expand Down
51 changes: 50 additions & 1 deletion src/app/screens/ConfirmPayment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,52 @@ import TextField from "../../components/Form/TextField";
export type Props = {
origin?: OriginData;
paymentRequest?: string;
metadata?: string;
};

// props contains one object which contains another two objects origin and paymentRequest. paymentRequest holds lnbc bolt 11 invoice
// and origin holds site name, image, description etc
// we have already passed an metadata through the SendPayment function of the weblnprovider
// so we need to add metadata in the props of the confirmPayment to render it

//this prompt is shown only for webln based thing
// when payment is done via lnurl qrcode we get prompt rendered present in screens/LNURLPay.tsx
// so currently we are adding metadata only for webln and not for any other thing
function ConfirmPayment(props: Props) {
console.log(props);

// converting props.metadata which holds json array into simple array
// no need for this , just pass props.details json array as it is and then run formattedMetadata function on that array.
const metadata = JSON.parse(props.metadata!);

// this function is called to parese the metadata to convert it into array
// this function only extracts description and full description if present and returns it in metadata const
// so like this we can parse received json array using json.parse and convert it into normal array, and then create a new function to extract values from that array


console.log(metadata);
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const auth = useAuth();
// holds all the data related to invoice
// props.paymentRequest holds the original lnurl.

console.log(props.paymentRequest);
const invoiceRef = useRef(
parsePaymentRequest({
request:
props.paymentRequest || (searchParams.get("paymentRequest") as string),
})
);
//console.log(invoiceRef);

// holds all the metadata related to site, name of site, icon of site etc
const originRef = useRef(props.origin || getOriginData());
// holds origin metadata as well as metadata passed via the webln
console.log(originRef.current);

const metadataRef = useRef(props.metadata)

const paymentRequestRef = useRef(
props.paymentRequest || searchParams.get("paymentRequest")
);
Expand All @@ -49,8 +82,11 @@ function ConfirmPayment(props: Props) {
const response = await utils.call(
"sendPayment",
{ paymentRequest: paymentRequestRef.current },
{ origin: originRef.current }
// adding metadata in the object which hold sites metadata as well
{ origin: originRef.current, metadata: metadataRef.current }

);

auth.fetchAccountInfo(); // Update balance.
msg.reply(response);
setSuccessMessage("Success, payment sent!");
Expand Down Expand Up @@ -102,6 +138,7 @@ function ConfirmPayment(props: Props) {

return (
<div>
{/* stores the webln enables sites name and icon and displays it in the confirm payment dialog */}
<PublisherCard
title={originRef.current.name}
image={originRef.current.icon}
Expand All @@ -111,9 +148,21 @@ function ConfirmPayment(props: Props) {
{!succesMessage ? (
<>
<div className="mb-8">
{/* shows payment summary i.e amount , description and we need to port metadata correctly here */}
{/* invoiceRef holds bolt 11 invoice, now a days they added new specification guidelines that invoice can contain metadata but no implementation is done in alby i thing to decode metadata from lnbc url
https://github.com/lightning/bolts/commit/2ab3a9f0221e601ba58ebb8bcaee55158b21bf80#diff-df5015da6e7bca53db91a45f0908a887b34664093f949400f01148e83ba75b93R713
so we have to see metadata passed from webln as a side data shall be included in invoice or not.
i think no. cause lnbc invoice is already send through SendPayment and on side we are sending payment metadata so i think they are not considering to include metadata in invoice
*/}
<PaymentSummary
amount={invoiceRef.current?.tokens}
description={invoiceRef.current?.description}
// we are passing json array directly and then formatting it using GetFormattedJson function in the PaymentSummary component and rendering it.



metadata={props.metadata}
/>
</div>

Expand Down
22 changes: 22 additions & 0 deletions src/app/screens/LNURLPay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const Dd = ({ children }: { children: React.ReactNode }) => (
<dd className="mb-4 dark:text-white">{children}</dd>
);

// screen is loaded when payment is done via lnurl
// both screens for webln payment and lnurl payment are different

function LNURLPay(props: Props) {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
Expand Down Expand Up @@ -177,7 +180,18 @@ function LNURLPay(props: Props) {
function getRecipient() {
if (!details?.metadata) return;
try {
//details is the object which contains all the information about the object
// metadata field of that object is parsed using json.parse
//details.metadata give array of array assigned to the metadata field i.e [[]]
// after json.parse that is converted into an array data structure

// but parsing is required only for specific purpose like here to get receipient
const metadata = JSON.parse(details.metadata);

//console.log(metadata);

// console.log(details);

const identifier = metadata.find(
([type]: [string]) => type === "text/identifier"
);
Expand All @@ -188,11 +202,18 @@ function LNURLPay(props: Props) {
return details.domain;
}


// this function is called to parese the metadata to convert it into array
// this function only extracts description and full description if present and returns it in metadata const
// so like this we can parse received json array using json.parse and convert it into normal array, and then create a new function to extract values from that array
function formattedMetadata(
metadataJSON: string
): [string, string | React.ReactNode][] {
try {
// here we are already parsing the metadata so no need to pass parsed metadata directly pass json array
const metadata = JSON.parse(metadataJSON);
// console.log(metadata);

return metadata
.map(([type, content]: [string, string]) => {
if (type === "text/plain") {
Expand Down Expand Up @@ -282,6 +303,7 @@ function LNURLPay(props: Props) {
<>
<Dt>Send payment to</Dt>
<Dd>{getRecipient()}</Dd>
{/* function is used on details.metadata which is json array, that json arrary is passed to this function it functions processes it and returns the valid json file */}
{formattedMetadata(details.metadata).map(([dt, dd]) => (
<>
<Dt>{dt}</Dt>
Expand Down
1 change: 1 addition & 0 deletions src/declarations.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
interface PaymentRequestDetails {
metadata: string;
chain_address?: string;
cltv_delta: number;
created_at: string;
Expand Down
3 changes: 3 additions & 0 deletions src/extension/background-script/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ const routes = {
ln: ln,
accounts: accounts,
*/

addAllowance: allowances.add,

// this helps in enabling the webln , so every webln shall have its route or port through which it triggers the browser
enable: allowances.enable,
getAllowance: allowances.get,
getAllowanceById: allowances.getById,
Expand Down
14 changes: 12 additions & 2 deletions src/extension/inpage-script/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import WebLNProvider from "../ln/webln";

// if page is loaded
if (document) {
// instantiate class object
window.webln = new WebLNProvider();

// Intercept any `lightning:` requests
// event listener which listens to a partcular event
window.addEventListener("click", (ev) => {

const target = ev.target;
if (!target || !target.closest) {
return;
}
//event listener triggers only for lightning prefix and lnurl.
const lightningLink = target.closest('[href^="lightning:" i]');
const lnurlLink = target.closest('[href^="lnurl" i]');
const bitcoinLinkWithLighting = target.closest('[href*="lightning=ln" i]'); // links with a lightning parameter and a value that starts with ln: payment requests (lnbc...) or lnurl (lnurl*)
Expand Down Expand Up @@ -47,12 +52,15 @@ if (document) {
if (paymentRequest && paymentRequest.match(/(\S+@\S+)/)) {
lnurl = paymentRequest.match(/(\S+@\S+)/)[1];
}

// window.webln contains the objec of the class WeblnProvider
// so we can calling enable() function present in provider class. and after enalbed we are using callback function to process the result.
window.webln.enable().then((response) => {
if (!response.enabled) {
return;
}
// if webln enalbed for the particular site
if (lnurl) {
// if its lnurl, call lnurl() method present in webln provider
return window.webln
.lnurl(lnurl)
.then((r) => {
Expand All @@ -63,11 +71,13 @@ if (document) {
alert(`Error: ${e.message}`);
});
}
// here we are executing sendPayment method
return window.webln
//webln sendpayment method
.sendPayment(paymentRequest)
.then((r) => {
console.log(r);
//alert(JSON.stringify(r));
alert(JSON.stringify(r));
})
.catch((e) => {
console.log(e);
Expand Down
Loading

0 comments on commit ed6f755

Please sign in to comment.