mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-20 14:05:27 +01:00
ADD: pay zero-amount (tip) invoices
This commit is contained in:
parent
6eb8dbfeca
commit
4c1affead1
4 changed files with 98 additions and 6 deletions
|
@ -247,4 +247,69 @@ describe('LightningCustodianWallet', () => {
|
|||
assert.equal(lOld.balance - oldBalance, 1);
|
||||
assert.equal(lNew.balance, 0);
|
||||
});
|
||||
|
||||
it('can pay free amount (tip) invoice', async function() {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100 * 1000;
|
||||
if (!process.env.BLITZHUB) {
|
||||
console.error('process.env.BLITZHUB not set, skipped');
|
||||
return;
|
||||
}
|
||||
|
||||
// fetchig invoice from tippin.me :
|
||||
|
||||
const api = new Frisbee({
|
||||
baseURI: 'https://tippin.me',
|
||||
});
|
||||
const res = await api.post('/lndreq/newinvoice.php', {
|
||||
headers: {
|
||||
Origin: 'https://tippin.me',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8',
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
Accept: 'application/json, text/javascript, */*; q=0.01',
|
||||
},
|
||||
body: 'userid=1188&username=overtorment&istaco=0&customAmnt=0&customMemo=',
|
||||
});
|
||||
|
||||
let json;
|
||||
let invoice;
|
||||
if (res && res.body && (json = JSON.parse(res.body)) && json.message) {
|
||||
invoice = json.message;
|
||||
} else {
|
||||
throw new Error('tippin.me problem: ' + JSON.stringify(res));
|
||||
}
|
||||
|
||||
// --> use to pay specific invoice
|
||||
// invoice =
|
||||
// 'lnbc1pwrp35spp5z62nvj8yw6luq7ns4a8utpwn2qkkdwdt0ludwm54wjeazk2xv5wsdpu235hqurfdcsx7an9wf6x7undv4h8ggpgw35hqurfdchx6eff9p6nzvfc8q5scqzysxqyz5vqj8xq6wz6dezmunw6qxleuw67ensjnt3fldltrmmkvzurge0dczpn94fkwwh7hkh5wqrhsvfegtvhswn252hn6uw5kx99dyumz4v5n9sp337py2';
|
||||
|
||||
let l2 = new LightningCustodianWallet();
|
||||
l2.setSecret(process.env.BLITZHUB);
|
||||
await l2.authorize();
|
||||
await l2.fetchTransactions();
|
||||
await l2.fetchBalance();
|
||||
let oldBalance = +l2.balance;
|
||||
let txLen = l2.transactions_raw.length;
|
||||
|
||||
let decoded = await l2.decodeInvoice(invoice);
|
||||
assert.ok(decoded.payment_hash);
|
||||
assert.ok(decoded.description);
|
||||
assert.equal(+decoded.num_satoshis, 0);
|
||||
|
||||
await l2.checkRouteInvoice(invoice);
|
||||
|
||||
let start = +new Date();
|
||||
await l2.payInvoice(invoice, 3);
|
||||
let end = +new Date();
|
||||
if ((end - start) / 1000 > 9) {
|
||||
console.warn('payInvoice took', (end - start) / 1000, 'sec');
|
||||
}
|
||||
|
||||
await l2.fetchTransactions();
|
||||
assert.equal(l2.transactions_raw.length, txLen + 1);
|
||||
// transactions became more after paying an invoice
|
||||
|
||||
await l2.fetchBalance();
|
||||
assert.equal(oldBalance - l2.balance, 3);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -102,9 +102,9 @@ export class LightningCustodianWallet extends LegacyWallet {
|
|||
this.secret = 'lndhub://' + json.login + ':' + json.password;
|
||||
}
|
||||
|
||||
async payInvoice(invoice) {
|
||||
async payInvoice(invoice, freeAmount = 0) {
|
||||
let response = await this._api.post('/payinvoice', {
|
||||
body: { invoice: invoice },
|
||||
body: { invoice: invoice, amount: freeAmount },
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import prompt from 'react-native-prompt-android';
|
||||
|
||||
module.exports = (title, text, isCancelable = true) => {
|
||||
module.exports = (title, text, isCancelable = true, type = 'secure-text') => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const buttons = isCancelable
|
||||
? [
|
||||
|
@ -30,7 +30,7 @@ module.exports = (title, text, isCancelable = true) => {
|
|||
];
|
||||
|
||||
prompt(title, text, buttons, {
|
||||
type: 'secure-text',
|
||||
type: type,
|
||||
cancelable: isCancelable,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ let BlueApp = require('../../BlueApp');
|
|||
let currency = require('../../currency');
|
||||
let EV = require('../../events');
|
||||
let loc = require('../../loc');
|
||||
let prompt = require('../../prompt');
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
export default class ScanLndInvoice extends React.Component {
|
||||
|
@ -92,6 +93,14 @@ export default class ScanLndInvoice extends React.Component {
|
|||
let decoded;
|
||||
try {
|
||||
decoded = await w.decodeInvoice(data);
|
||||
let freeAmount = 0;
|
||||
while (+decoded.num_satoshis === 0) {
|
||||
freeAmount = await prompt('This is free amount invoice', 'How many satoshis do you want to tip?', false, 'numeric');
|
||||
freeAmount = parseInt(freeAmount);
|
||||
if (!isNaN(freeAmount) && freeAmount > 0) {
|
||||
decoded.num_satoshis = freeAmount;
|
||||
}
|
||||
}
|
||||
|
||||
let expiresIn = (decoded.timestamp * 1 + decoded.expiry * 1) * 1000; // ms
|
||||
if (+new Date() > expiresIn) {
|
||||
|
@ -105,6 +114,7 @@ export default class ScanLndInvoice extends React.Component {
|
|||
invoice: data,
|
||||
decoded,
|
||||
expiresIn,
|
||||
freeAmount,
|
||||
destination: data,
|
||||
});
|
||||
} catch (Err) {
|
||||
|
@ -143,7 +153,7 @@ export default class ScanLndInvoice extends React.Component {
|
|||
let start = +new Date();
|
||||
let end;
|
||||
try {
|
||||
await fromWallet.payInvoice(this.state.invoice);
|
||||
await fromWallet.payInvoice(this.state.invoice, this.state.freeAmount);
|
||||
end = +new Date();
|
||||
} catch (Err) {
|
||||
console.log(Err.message);
|
||||
|
@ -170,7 +180,24 @@ export default class ScanLndInvoice extends React.Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
||||
<TouchableWithoutFeedback
|
||||
onPress={async () => {
|
||||
if (this.state.freeAmount) {
|
||||
// must ask user again about the amount
|
||||
let freeAmount = await prompt('This is free amount invoice', 'How many satoshis do you want to tip?', false, 'numeric');
|
||||
freeAmount = parseInt(freeAmount);
|
||||
if (!isNaN(freeAmount) && freeAmount > 0) {
|
||||
let decoded = this.state.decoded;
|
||||
decoded.num_satoshis = freeAmount;
|
||||
this.setState({ decoded, freeAmount });
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
} else {
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
}}
|
||||
accessible={false}
|
||||
>
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<Text style={{ textAlign: 'center', fontSize: 50, fontWeight: '700', color: '#2f5fb3' }}>
|
||||
{this.state.hasOwnProperty('decoded') &&
|
||||
|
|
Loading…
Add table
Reference in a new issue