Merge pull request #5130 from BlueWallet/fix-5120

FIX: cant reliably pay lnurl invoices when current currency is fiat (…
This commit is contained in:
GLaDOS 2022-10-21 08:24:02 +01:00 committed by GitHub
commit 7ae6289cf5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 5 deletions

View file

@ -289,6 +289,18 @@ export default class Lnurl {
return this?._lnurlPayServicePayload?.commentAllowed ? parseInt(this._lnurlPayServicePayload.commentAllowed) : false; return this?._lnurlPayServicePayload?.commentAllowed ? parseInt(this._lnurlPayServicePayload.commentAllowed) : false;
} }
getMin() {
return this?._lnurlPayServicePayload?.min ? parseInt(this._lnurlPayServicePayload.min) : false;
}
getMax() {
return this?._lnurlPayServicePayload?.max ? parseInt(this._lnurlPayServicePayload.max) : false;
}
getAmount() {
return this.getMin();
}
authenticate(secret) { authenticate(secret) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!this._lnurl) throw new Error('this._lnurl is not set'); if (!this._lnurl) throw new Error('this._lnurl is not set');

View file

@ -25,13 +25,21 @@ import alert from '../../components/Alert';
const prompt = require('../../helpers/prompt'); const prompt = require('../../helpers/prompt');
const currency = require('../../blue_modules/currency'); const currency = require('../../blue_modules/currency');
/**
* if user has default currency - fiat, attempting to pay will trigger conversion from entered in input field fiat value
* to satoshi, and attempt to pay this satoshi value, which might be a little bit off from `min` & `max` values
* provided by LnUrl. thats why we cache initial precise conversion rate so the reverse conversion wont be off.
*/
const _cacheFiatToSat = {};
const LnurlPay = () => { const LnurlPay = () => {
const { wallets } = useContext(BlueStorageContext); const { wallets } = useContext(BlueStorageContext);
const { walletID, lnurl } = useRoute().params; const { walletID, lnurl } = useRoute().params;
/** @type {LightningCustodianWallet} */
const wallet = wallets.find(w => w.getID() === walletID); const wallet = wallets.find(w => w.getID() === walletID);
const [unit, setUnit] = useState(wallet.getPreferredBalanceUnit()); const [unit, setUnit] = useState(wallet.getPreferredBalanceUnit());
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [LN, setLN] = useState(); const [_LN, setLN] = useState();
const [payButtonDisabled, setPayButtonDisabled] = useState(true); const [payButtonDisabled, setPayButtonDisabled] = useState(true);
const [payload, setPayload] = useState(); const [payload, setPayload] = useState();
const { setParams, pop, navigate } = useNavigation(); const { setParams, pop, navigate } = useNavigation();
@ -73,13 +81,21 @@ const LnurlPay = () => {
useEffect(() => { useEffect(() => {
if (payload) { if (payload) {
let newAmount = payload.min; /** @type {Lnurl} */
const LN = _LN;
let originalSatAmount;
let newAmount = (originalSatAmount = LN.getMin());
if (!newAmount) {
alert('Internal error: incorrect LNURL amount');
return;
}
switch (unit) { switch (unit) {
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
newAmount = currency.satoshiToBTC(newAmount); newAmount = currency.satoshiToBTC(newAmount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
newAmount = currency.satoshiToLocalCurrency(newAmount, false); newAmount = currency.satoshiToLocalCurrency(newAmount, false);
_cacheFiatToSat[newAmount] = originalSatAmount;
break; break;
} }
setAmount(newAmount); setAmount(newAmount);
@ -94,6 +110,7 @@ const LnurlPay = () => {
const pay = async () => { const pay = async () => {
setPayButtonDisabled(true); setPayButtonDisabled(true);
/** @type {Lnurl} */ /** @type {Lnurl} */
const LN = _LN;
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled(); const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) { if (isBiometricsEnabled) {
@ -111,12 +128,14 @@ const LnurlPay = () => {
amountSats = currency.btcToSatoshi(amountSats); amountSats = currency.btcToSatoshi(amountSats);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
amountSats = currency.btcToSatoshi(currency.fiatToBTC(amountSats)); if (_cacheFiatToSat[amount]) {
amountSats = _cacheFiatToSat[amount];
} else {
amountSats = currency.btcToSatoshi(currency.fiatToBTC(amountSats));
}
break; break;
} }
/** @type {LightningCustodianWallet} */
let bolt11payload; let bolt11payload;
try { try {
let comment; let comment;

View file

@ -178,6 +178,9 @@ describe('LNURL', function () {
assert.strictEqual(LN.getImage(), undefined); assert.strictEqual(LN.getImage(), undefined);
assert.strictEqual(LN.getLnurl(), 'lnurl1dp68gurn8ghj7cmgv96zucnvd9u8gampd3kx2apwvdhk6tmpwp5j7um9dejz6ar90p6q3eqkzd'); assert.strictEqual(LN.getLnurl(), 'lnurl1dp68gurn8ghj7cmgv96zucnvd9u8gampd3kx2apwvdhk6tmpwp5j7um9dejz6ar90p6q3eqkzd');
assert.strictEqual(LN.getCommentAllowed(), 144); assert.strictEqual(LN.getCommentAllowed(), 144);
assert.strictEqual(LN.getAmount(), LN.getMin());
assert.strictEqual(LN.getMin(), 1);
assert.strictEqual(LN.getMax(), 1000000);
// mock only to get fetched url: // mock only to get fetched url:
let urlUsed = ''; let urlUsed = '';