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

Pin support (LUD-21) #33

Merged
merged 9 commits into from
May 26, 2024
Merged

Conversation

X-Hades-X
Copy link
Contributor

This PR implements the LUD-21 as specified here https://github.com/bitcoin-ring/luds/blob/withdraw-pin/21.md
This LUD has not been merged to as official LNURL LUD

Adds a pin pad that appears inside a bottom drawer to enter a 4 digit pin if the amount that has to be paid is bigger then the pinLimit value of the LNURLw response.

@@ -49,7 +70,7 @@ export const useNfc = () => {
}, []);

const readingNfcLoop = useCallback(
async (pr: string) => {
async (pr: string, amount: number) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to pass the amount into this function to check if pin is required.

It is also needed for the commented out part, the lnurlp request as far as I understand. Was there a reason why it is commented out? Are there any bugs or is it a bad idea to add this parameter to the function?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LNURLp was commented as it require some additional work. We could do that in another PR :)
Adding the amount is okay.

if (debitCardData?.status === "OK" && !error) {
setIsNfcActionSuccess(true);
} else {
if (debitCardData?.status === "ERROR" && !error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the pin is wrong the response is in the debitCardData object not the error object. Is that a wrong implementation on my side? Should the server send another status then 200? I haven't seen a specification for that in the LUD-3.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's probably a mis-implementation on our side. You can keep the code like this for the moment.

Copy link
Owner

@SwissBitcoinPay SwissBitcoinPay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, there is quite a few of lint issues.
Please run npm run lint and fix the errors you see.

package.json Outdated
@@ -47,6 +47,7 @@
"react-dom": "18.2.0",
"react-i18next": "13.2.2",
"react-native": "0.73.2",
"react-native-animated-bottom-drawer": "^0.0.23",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For security reasons, we keep the version fixed like this:

Suggested change
"react-native-animated-bottom-drawer": "^0.0.23",
"react-native-animated-bottom-drawer": "0.0.23",

Please do npm install again after changing

package.json Outdated
@@ -58,6 +59,7 @@
"react-native-dotenv": "3.4.9",
"react-native-linear-gradient": "2.8.3",
"react-native-nfc-manager": "3.14.11",
"react-native-pin-view": "^3.0.3",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For security reasons, we keep the version fixed like this:

Suggested change
"react-native-pin-view": "^3.0.3",
"react-native-pin-view": "3.0.3",

Please do npm install again after changing

@@ -49,7 +70,7 @@ export const useNfc = () => {
}, []);

const readingNfcLoop = useCallback(
async (pr: string) => {
async (pr: string, amount: number) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LNURLp was commented as it require some additional work. We could do that in another PR :)
Adding the amount is okay.

@@ -114,15 +135,31 @@ export const useNfc = () => {
tag: "withdrawRequest";
callback: string;
k1: string;
pinLimit: number;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As pinLimit is not always defined, you need to add a ? as "possibly undefined"

Suggested change
pinLimit: number;
pinLimit?: number;

}>(cardData);

let pin = "";
if (cardDataResponse.pinLimit !== undefined) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify it with:

Suggested change
if (cardDataResponse.pinLimit !== undefined) {
if (cardDataResponse.pinLimit) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that the pinLimit could be set to 0. But then one could argue that means it is "disabled" since the number in the pinLimit is the min amounted needed before asking the pin and the smallest possible number for that would be 1.
How should we implement it?

Copy link
Collaborator

@jimmydjabali jimmydjabali May 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. The doc says value must be a positive integer (including 0), but also to withdraw an amount equal to or greater [...].
But as we can't really withdraw 0 sat, I agree with you that 0 could means "disabled".
As this is not clear, you can keep it as cardDataResponse.pinLimit !== undefined and ignore my initial comment.

if (debitCardData?.status === "OK" && !error) {
setIsNfcActionSuccess(true);
} else {
if (debitCardData?.status === "ERROR" && !error) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's probably a mis-implementation on our side. You can keep the code like this for the moment.

@@ -32,6 +32,8 @@ import { faBitcoin } from "@fortawesome/free-brands-svg-icons";
import axios from "axios";
import * as S from "./styled";

import { PinPad } from "../PinPad";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do the following:

  1. Move the PinPad component (folder) to src/components
  2. Add export { PinPad } from "./PinPad"; to src/components/index.ts
  3. Change this line to:
Suggested change
import { PinPad } from "../PinPad";
import { PinPad } from "@components";

import { faDeleteLeft, faUnlock } from "@fortawesome/free-solid-svg-icons";

export const PinPad = (props) => {
const pinView = useRef(null);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above the component, you can add the following:

type PinViewFunctions = {
  clearAll: () => void;
};

And change this line to

Suggested change
const pinView = useRef(null);
const pinView = useRef<PinViewFunctions>(null);

import { Text, Icon } from "@components";
import { faDeleteLeft, faUnlock } from "@fortawesome/free-solid-svg-icons";

export const PinPad = (props) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to type the props, like we do on other components.

Comment on lines 19 to 41
const styles = StyleSheet.create({
container: {
backgroundColor: "rgba(0,0,0,0.5)",
},
handleContainer: {
backgroundColor: "transparent",
},
pinPad: {
backgroundColor: "transparent",
alignItems: "center",
flex: 1,
},
pinPadTitle: {
paddingTop: 48,
paddingBottom: 24,
color: "rgba(255,255,255,1)",
fontSize: 48,
},
whiteBorder: {
borderWidth: 1,
borderColor: "#FFF",
},
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually we styled-components.
Can you try to migrate this to styled.ts. Check other styled.ts files in the repo to see how it works. It's pretty simple!

And it help to keep the component's logic files clean.

@X-Hades-X
Copy link
Contributor Author

Additionally, there is quite a few of lint issues. Please run npm run lint and fix the errors you see.

image

I can't get rid of these whatever I do. I don't understand why it is telling me this because the code clearly works. What can I do about this?

@X-Hades-X
Copy link
Contributor Author

This I also can't solve and don't understand what it needs
image

Comment on lines 23 to 40
const [ pinResolver, setPinResolver ] = useState({ resolve: undefined })

const setPin = (pin: string) => {
if(pinResolver.resolve) {
pinResolver.resolve(pin);
}
}

const getPin = useCallback(async () => {
const pinInputPromise = () => {
let _pinResolver;
return [ new Promise(( resolve ) => {
_pinResolver = resolve
}), _pinResolver]
}

const [ promise, resolve ] = pinInputPromise()
setPinResolver({ resolve })
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can fix TS issues here by committing this

Suggested change
const [ pinResolver, setPinResolver ] = useState({ resolve: undefined })
const setPin = (pin: string) => {
if(pinResolver.resolve) {
pinResolver.resolve(pin);
}
}
const getPin = useCallback(async () => {
const pinInputPromise = () => {
let _pinResolver;
return [ new Promise(( resolve ) => {
_pinResolver = resolve
}), _pinResolver]
}
const [ promise, resolve ] = pinInputPromise()
setPinResolver({ resolve })
const [pinResolver, setPinResolver] = useState<{
resolve: (v: string) => void;
}>();
const setPin = (pin: string) => {
if (pinResolver?.resolve) {
pinResolver.resolve(pin);
}
};
const getPin = useCallback(async () => {
const pinInputPromise = () => {
let _pinResolver;
return [
new Promise<string>((resolve) => {
_pinResolver = resolve;
}),
_pinResolver
];
};
const [promise, resolve] = pinInputPromise();
setPinResolver({ resolve } as unknown as { resolve: (v: string) => void });

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had something like that but wasn't thinkin about casting first to unknown. Thanks 👍

buttonViewStyle={S.PinViewStyles.whiteBorder}
buttonTextStyle={{ color: "#FFF" }}
onButtonPress={key => setButtonPressed(key)}
customLeftButton={showRemoveButton ? <Icon icon={faDeleteLeft} size={36} color={"#FFF"} /> : undefined}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the TS issue here, you need to replace this lin with:

Suggested change
customLeftButton={showRemoveButton ? <Icon icon={faDeleteLeft} size={36} color={"#FFF"} /> : undefined}
customLeftButton={showRemoveButton ? LeftButton : undefined}

And add a LeftButton component below:

const LeftButton = () => <Icon icon={faDeleteLeft} size={36} color={"#FFF"} />;

Copy link
Contributor Author

@X-Hades-X X-Hades-X May 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had <LeftButton />, so that's how you do it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I do it without <> it never appears

</S.PinPadTitle>
<ReactNativePinView
inputSize={32}
ref={pinView}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid a new TS issue here, add a // @ts-ignore :

Suggested change
ref={pinView}
// @ts-ignore
ref={pinView}

@SwissBitcoinPay SwissBitcoinPay merged commit ec62cc6 into SwissBitcoinPay:main May 26, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants