astra-lightning 1.1.6 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +6 -0
- package/lnd_methods/index.js +4 -0
- package/lnd_methods/offchain/index.d.ts +1 -0
- package/lnd_methods/offchain/index.js +4 -0
- package/lnd_methods/offchain/is_taproot_invoice_payable.d.ts +35 -0
- package/lnd_methods/offchain/is_taproot_invoice_payable.js +88 -0
- package/lnd_methods/offchain/pay_via_taproot_payment_request.js +105 -0
- package/package.json +2 -2
- package/test/test_3hop_payable.js +68 -0
- package/test/test_invoice_payable.js +28 -0
- package/test/test_tapd_decode.js +34 -0
- package/test.js +36 -19
package/index.js
CHANGED
|
@@ -159,7 +159,9 @@ const {verifyBytesSignature} = require('./lnd_methods');
|
|
|
159
159
|
const {verifyChainAddressMessage} = require('./lnd_methods');
|
|
160
160
|
const {verifyMessage} = require('./lnd_methods');
|
|
161
161
|
const { decodeAssetPayReq } = require('./lnd_methods');
|
|
162
|
+
const { isTaprootInvoicePayable } = require('./lnd_methods');
|
|
162
163
|
const { payTaprootInvoice } = require('./lnd_methods');
|
|
164
|
+
const { payViaTaprootPaymentRequest } = require('./lnd_methods');
|
|
163
165
|
|
|
164
166
|
module.exports = {
|
|
165
167
|
addAdvertisedFeature,
|
|
@@ -324,4 +326,8 @@ module.exports = {
|
|
|
324
326
|
verifyBytesSignature,
|
|
325
327
|
verifyChainAddressMessage,
|
|
326
328
|
verifyMessage,
|
|
329
|
+
decodeAssetPayReq,
|
|
330
|
+
isTaprootInvoicePayable,
|
|
331
|
+
payTaprootInvoice,
|
|
332
|
+
payViaTaprootPaymentRequest,
|
|
327
333
|
};
|
package/lnd_methods/index.js
CHANGED
|
@@ -158,7 +158,9 @@ const {verifyBytesSignature} = require('./signer');
|
|
|
158
158
|
const {verifyChainAddressMessage} = require('./onchain');
|
|
159
159
|
const {verifyMessage} = require('./message');
|
|
160
160
|
const { decodeAssetPayReq } = require('./offchain');
|
|
161
|
+
const { isTaprootInvoicePayable } = require('./offchain');
|
|
161
162
|
const { payTaprootInvoice } = require('./offchain');
|
|
163
|
+
const { payViaTaprootPaymentRequest } = require('./offchain');
|
|
162
164
|
|
|
163
165
|
module.exports = {
|
|
164
166
|
addAdvertisedFeature,
|
|
@@ -321,5 +323,7 @@ module.exports = {
|
|
|
321
323
|
verifyChainAddressMessage,
|
|
322
324
|
verifyMessage,
|
|
323
325
|
decodeAssetPayReq,
|
|
326
|
+
isTaprootInvoicePayable,
|
|
324
327
|
payTaprootInvoice,
|
|
328
|
+
payViaTaprootPaymentRequest,
|
|
325
329
|
};
|
|
@@ -57,7 +57,9 @@ const updateRoutingFees = require('./update_routing_fees');
|
|
|
57
57
|
const verifyBackup = require('./verify_backup');
|
|
58
58
|
const verifyBackups = require('./verify_backups');
|
|
59
59
|
const decodeAssetPayReq = require('./decode_asset_pay_req');
|
|
60
|
+
const isTaprootInvoicePayable = require('./is_taproot_invoice_payable');
|
|
60
61
|
const payTaprootInvoice = require('./pay_taproot_invoice');
|
|
62
|
+
const payViaTaprootPaymentRequest = require('./pay_via_taproot_payment_request');
|
|
61
63
|
|
|
62
64
|
module.exports = {
|
|
63
65
|
connectWatchtower,
|
|
@@ -119,5 +121,7 @@ module.exports = {
|
|
|
119
121
|
verifyBackup,
|
|
120
122
|
verifyBackups,
|
|
121
123
|
decodeAssetPayReq,
|
|
124
|
+
isTaprootInvoicePayable,
|
|
122
125
|
payTaprootInvoice,
|
|
126
|
+
payViaTaprootPaymentRequest,
|
|
123
127
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthenticatedLightningArgs,
|
|
3
|
+
AuthenticatedLightningMethod,
|
|
4
|
+
Routes,
|
|
5
|
+
} from '../../typescript';
|
|
6
|
+
|
|
7
|
+
export type IsTaprootInvoicePayableArgs = AuthenticatedLightningArgs<{
|
|
8
|
+
/** Maximum Fee Tokens To Pay Number */
|
|
9
|
+
max_fee?: number;
|
|
10
|
+
/** Time to Spend Finding a Route Milliseconds Number */
|
|
11
|
+
pathfinding_timeout?: number;
|
|
12
|
+
/** BOLT-11 Payment Request String */
|
|
13
|
+
request: string;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
export type IsTaprootInvoicePayableResult = {
|
|
17
|
+
/** Destination Public Key Hex String */
|
|
18
|
+
destination?: string;
|
|
19
|
+
/** Is Invoice Payable Boolean */
|
|
20
|
+
is_payable: boolean;
|
|
21
|
+
/** Route Hints Array */
|
|
22
|
+
routes?: Routes;
|
|
23
|
+
/** Invoice Amount Tokens Number */
|
|
24
|
+
tokens?: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Determine if a Taproot asset invoice is payable by probing the LN route
|
|
29
|
+
*
|
|
30
|
+
* Requires `offchain:write` permission
|
|
31
|
+
*/
|
|
32
|
+
export const isTaprootInvoicePayable: AuthenticatedLightningMethod<
|
|
33
|
+
IsTaprootInvoicePayableArgs,
|
|
34
|
+
IsTaprootInvoicePayableResult
|
|
35
|
+
>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {returnResult} = require('asyncjs-util');
|
|
3
|
+
const {decodePaymentRequest} = require('lightning');
|
|
4
|
+
const {isDestinationPayable} = require('lightning');
|
|
5
|
+
|
|
6
|
+
/** Determine if a Taproot asset invoice is payable by probing the LN route
|
|
7
|
+
|
|
8
|
+
Requires `offchain:write` permission
|
|
9
|
+
|
|
10
|
+
Uses the routing hints embedded in the BOLT-11 invoice to test if the
|
|
11
|
+
Lightning Network route to the destination exists. This supports multi-hop
|
|
12
|
+
paths (e.g., Alice → Bob → Carol) because the invoice contains routing
|
|
13
|
+
hints that allow LND to discover the path.
|
|
14
|
+
|
|
15
|
+
Note: this checks LN-level reachability, not asset channel availability.
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
lnd: <Authenticated LND API Object>
|
|
19
|
+
request: <BOLT-11 Payment Request String>
|
|
20
|
+
[pathfinding_timeout]: <Time to Spend Finding a Route Milliseconds Number>
|
|
21
|
+
[max_fee]: <Maximum Fee Tokens To Pay Number>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@returns via cbk or Promise
|
|
25
|
+
{
|
|
26
|
+
is_payable: <Is Invoice Payable Boolean>
|
|
27
|
+
[destination]: <Destination Public Key Hex String>
|
|
28
|
+
[routes]: <Route Hints Array>
|
|
29
|
+
[tokens]: <Invoice Amount Tokens Number>
|
|
30
|
+
}
|
|
31
|
+
*/
|
|
32
|
+
module.exports = (args, cbk) => {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
return asyncAuto({
|
|
35
|
+
// Check arguments
|
|
36
|
+
validate: cbk => {
|
|
37
|
+
if (!args.lnd) {
|
|
38
|
+
return cbk([400, 'ExpectedAuthenticatedLndToCheckInvoicePayability']);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!args.request) {
|
|
42
|
+
return cbk([400, 'ExpectedPaymentRequestToCheckInvoicePayability']);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return cbk();
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Decode the invoice to extract destination and routing hints
|
|
49
|
+
decode: ['validate', ({}, cbk) => {
|
|
50
|
+
return decodePaymentRequest({
|
|
51
|
+
lnd: args.lnd,
|
|
52
|
+
request: args.request,
|
|
53
|
+
},
|
|
54
|
+
cbk);
|
|
55
|
+
}],
|
|
56
|
+
|
|
57
|
+
// Probe the destination using routing hints from the invoice
|
|
58
|
+
probe: ['decode', ({decode}, cbk) => {
|
|
59
|
+
return isDestinationPayable({
|
|
60
|
+
destination: decode.destination,
|
|
61
|
+
lnd: args.lnd,
|
|
62
|
+
max_fee: args.max_fee,
|
|
63
|
+
pathfinding_timeout: args.pathfinding_timeout,
|
|
64
|
+
routes: decode.routes,
|
|
65
|
+
tokens: decode.tokens || 1,
|
|
66
|
+
},
|
|
67
|
+
(err, res) => {
|
|
68
|
+
if (!!err) {
|
|
69
|
+
return cbk(null, {
|
|
70
|
+
is_payable: false,
|
|
71
|
+
destination: decode.destination,
|
|
72
|
+
routes: decode.routes,
|
|
73
|
+
tokens: decode.tokens,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return cbk(null, {
|
|
78
|
+
is_payable: !!res && !!res.is_payable,
|
|
79
|
+
destination: decode.destination,
|
|
80
|
+
routes: decode.routes,
|
|
81
|
+
tokens: decode.tokens,
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}],
|
|
85
|
+
},
|
|
86
|
+
returnResult({reject, resolve, of: 'probe'}, cbk));
|
|
87
|
+
});
|
|
88
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const hexAsBuffer = (hex) => (!!hex ? Buffer.from(hex, "hex") : undefined);
|
|
2
|
+
|
|
3
|
+
/** Convert buffers to hex strings in an object
|
|
4
|
+
|
|
5
|
+
{
|
|
6
|
+
obj: <Object to Convert>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@returns
|
|
10
|
+
<Converted Object>
|
|
11
|
+
*/
|
|
12
|
+
function convertBuffers(obj) {
|
|
13
|
+
if (Array.isArray(obj)) {
|
|
14
|
+
return obj.map(convertBuffers);
|
|
15
|
+
} else if (typeof obj === "object" && obj !== null) {
|
|
16
|
+
if (Buffer.isBuffer(obj)) {
|
|
17
|
+
return obj.toString("hex");
|
|
18
|
+
} else {
|
|
19
|
+
const result = {};
|
|
20
|
+
Object.keys(obj).forEach((key) => {
|
|
21
|
+
result[key] = convertBuffers(obj[key]);
|
|
22
|
+
});
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
return obj;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Pay via Taproot payment request
|
|
31
|
+
|
|
32
|
+
Requires `offchain:write` permission
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
asset_amount: <Asset Amount String>
|
|
36
|
+
asset_id: <Asset ID Hex String>
|
|
37
|
+
[group_key]: <Group Key Hex String>
|
|
38
|
+
payment_request: <LND Payment Request Object>
|
|
39
|
+
[peer_pubkey]: <Peer Public Key Hex String>
|
|
40
|
+
[price_oracle_metadata]: <Price Oracle Metadata String>
|
|
41
|
+
tpr: <Authenticated TPR API Object>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@returns via Promise
|
|
45
|
+
{
|
|
46
|
+
[accepted_sell_order]: <Accepted Sell Order Object>
|
|
47
|
+
[failure_reason]: <Failure Reason String>
|
|
48
|
+
[payment_result]: <Payment Result Object>
|
|
49
|
+
}
|
|
50
|
+
*/
|
|
51
|
+
module.exports = (args) => {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
if (!args.tpr) {
|
|
54
|
+
return reject(new Error('ExpectedAuthenticatedTprToMakePayment'));
|
|
55
|
+
}
|
|
56
|
+
if (!args.asset_id) {
|
|
57
|
+
return reject(new Error('ExpectedAssetIdToMakePayment'));
|
|
58
|
+
}
|
|
59
|
+
if (!args.asset_amount) {
|
|
60
|
+
return reject(new Error('ExpectedAssetAmountToMakePayment'));
|
|
61
|
+
}
|
|
62
|
+
if (!args.payment_request) {
|
|
63
|
+
return reject(new Error('ExpectedPaymentRequestToMakePayment'));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const callRequest = {
|
|
67
|
+
asset_id: hexAsBuffer(args.asset_id),
|
|
68
|
+
asset_amount: args.asset_amount,
|
|
69
|
+
peer_pubkey: hexAsBuffer(args.peer_pubkey),
|
|
70
|
+
payment_request: args.payment_request,
|
|
71
|
+
price_oracle_metadata: args.price_oracle_metadata || undefined,
|
|
72
|
+
group_key: args.group_key ? hexAsBuffer(args.group_key) : undefined,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const sub = args.tpr.taproot_asset_channels.sendPayment(callRequest);
|
|
76
|
+
|
|
77
|
+
const ret = {
|
|
78
|
+
payment_result: null,
|
|
79
|
+
failure_reason: null,
|
|
80
|
+
accepted_sell_order: null,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
sub.on('data', response => {
|
|
84
|
+
if (response?.accepted_sell_order) {
|
|
85
|
+
ret.accepted_sell_order = response.accepted_sell_order;
|
|
86
|
+
}
|
|
87
|
+
if (response?.payment_result) {
|
|
88
|
+
ret.payment_result = response.payment_result;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
sub.on('error', err => {
|
|
94
|
+
if (err?.details && err.details.indexOf("EOF") === -1) {
|
|
95
|
+
ret.failure_reason = err.details;
|
|
96
|
+
return reject([503, 'UnexpectedPaymentError', {err}]);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
sub.on('end', () => {
|
|
101
|
+
sub.removeAllListeners();
|
|
102
|
+
return resolve(convertBuffers(ret));
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { authenticatedLndGrpc } = require('../index.js');
|
|
3
|
+
const { decodePaymentRequest, isDestinationPayable } = require('lightning');
|
|
4
|
+
|
|
5
|
+
const LND_MACAROON = "0201036c6e6402f801030a101b4023c36f0935c6b7c16a87731ce9a61201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620e876a6c742d8e80691218c6dbfb348223e67a8386418cb6e8346e91f56c662c9";
|
|
6
|
+
const LND_SOCKET = "127.0.0.1:8443";
|
|
7
|
+
const LND_TLS_CERT_PATH = "/Users/jim/.polar/networks/1/volumes/litd/alice/lit/tls.cert";
|
|
8
|
+
|
|
9
|
+
// Dave's 3-hop invoice
|
|
10
|
+
const daveInvoice = 'lnbcrt50u1p5eana8pp52nzxmlynxp9p702l29wsaxz7wlqpuvcvwwvhh0uuhgqnr3tgvgwsdqqcqzzsxqrrssrzjq0cejmct3flggm7d40m3un7whtfqpvpmzz9ycc3wdtz3ksj2f26aea2uffn04skg8gqqqqlgqqqqqqgq2qsp5nxlk85rnkph60ggvkf5udzfh3v0qpws2x48nmvtcya7aqqwz43ps9qxpqysgqq9jnm60aq5pvgp6x5xp6utx939z2f4mp3t5se2qzyw9ymppc93qyv9yz2nx29nv3l06c5jl8t2t7zgut5zh7v2nqzvsfz9u4590694qpne2jr9';
|
|
11
|
+
|
|
12
|
+
const bobPubkey = '031be2f091594e9909a3af76dafba75292da7abc3ffb0ef3ae6bca22b95fd56054';
|
|
13
|
+
const carolPubkey = '03f1996f0b8a7e846fcdabf71e4fcebad200b03b108a4c622e6ac51b424a4ab5dc';
|
|
14
|
+
|
|
15
|
+
async function run() {
|
|
16
|
+
const base64Cert = fs.readFileSync(LND_TLS_CERT_PATH).toString("base64");
|
|
17
|
+
const { lnd } = authenticatedLndGrpc({
|
|
18
|
+
cert: base64Cert,
|
|
19
|
+
macaroon: LND_MACAROON,
|
|
20
|
+
socket: LND_SOCKET,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
console.log('Decoding Dave invoice...');
|
|
24
|
+
const decode = await decodePaymentRequest({ lnd, request: daveInvoice });
|
|
25
|
+
|
|
26
|
+
// Clone the routes
|
|
27
|
+
const modifiedRoutes = JSON.parse(JSON.stringify(decode.routes));
|
|
28
|
+
|
|
29
|
+
// The existing hint only has Carol -> Dave
|
|
30
|
+
// modifiedRoutes[0] looks like:
|
|
31
|
+
// [ { public_key: 'Carol' }, { channel: '...', public_key: 'Dave', ... } ]
|
|
32
|
+
|
|
33
|
+
// We want to prepend the Bob -> Carol hop to connect Alice -> Bob -> Carol -> Dave
|
|
34
|
+
// We specify Bob as the entry point, then a fake/real edge to Carol, then the edge to Dave
|
|
35
|
+
const injectedRoute = [
|
|
36
|
+
{
|
|
37
|
+
public_key: bobPubkey // Hop 0: Entry node Bob
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
// Hop 1: Bob -> Carol Edge
|
|
41
|
+
base_fee_mtokens: "1000",
|
|
42
|
+
channel: "1x1x1", // Dummy short channel ID for Bob->Carol
|
|
43
|
+
cltv_delta: 40,
|
|
44
|
+
fee_rate: 1,
|
|
45
|
+
public_key: carolPubkey
|
|
46
|
+
},
|
|
47
|
+
// Hop 2: Carol -> Dave Edge (copy from existing)
|
|
48
|
+
modifiedRoutes[0][1]
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
console.log('\nModified Routes injected into probe:\n', JSON.stringify([injectedRoute], null, 2));
|
|
52
|
+
|
|
53
|
+
console.log('\nProbing 3-hop with injected routing hints...');
|
|
54
|
+
try {
|
|
55
|
+
const res = await isDestinationPayable({
|
|
56
|
+
lnd,
|
|
57
|
+
destination: decode.destination,
|
|
58
|
+
routes: [injectedRoute],
|
|
59
|
+
tokens: decode.tokens || 1,
|
|
60
|
+
pathfinding_timeout: 5000,
|
|
61
|
+
});
|
|
62
|
+
console.log('Result:', JSON.stringify(res, null, 2));
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.log('Error:', err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
run().catch(console.error);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { authenticatedLndGrpc, isTaprootInvoicePayable } = require('../index.js');
|
|
3
|
+
|
|
4
|
+
const LND_MACAROON = "0201036c6e6402f801030a101b4023c36f0935c6b7c16a87731ce9a61201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620e876a6c742d8e80691218c6dbfb348223e67a8386418cb6e8346e91f56c662c9";
|
|
5
|
+
const LND_SOCKET = "127.0.0.1:8443";
|
|
6
|
+
const LND_TLS_CERT_PATH = "/Users/jim/.polar/networks/1/volumes/litd/alice/lit/tls.cert";
|
|
7
|
+
|
|
8
|
+
// Carol's invoice (contains routing hints via Bob)
|
|
9
|
+
const carolInvoice = 'lnbcrt50u1p5eana8pp52nzxmlynxp9p702l29wsaxz7wlqpuvcvwwvhh0uuhgqnr3tgvgwsdqqcqzzsxqrrssrzjq0cejmct3flggm7d40m3un7whtfqpvpmzz9ycc3wdtz3ksj2f26aea2uffn04skg8gqqqqlgqqqqqqgq2qsp5nxlk85rnkph60ggvkf5udzfh3v0qpws2x48nmvtcya7aqqwz43ps9qxpqysgqq9jnm60aq5pvgp6x5xp6utx939z2f4mp3t5se2qzyw9ymppc93qyv9yz2nx29nv3l06c5jl8t2t7zgut5zh7v2nqzvsfz9u4590694qpne2jr9';
|
|
10
|
+
|
|
11
|
+
async function run() {
|
|
12
|
+
const base64Cert = fs.readFileSync(LND_TLS_CERT_PATH).toString("base64");
|
|
13
|
+
const { lnd } = authenticatedLndGrpc({
|
|
14
|
+
cert: base64Cert,
|
|
15
|
+
macaroon: LND_MACAROON,
|
|
16
|
+
socket: LND_SOCKET,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
console.log('Testing isTaprootInvoicePayable with Carol invoice...');
|
|
20
|
+
try {
|
|
21
|
+
const result = await isTaprootInvoicePayable({ lnd, request: carolInvoice });
|
|
22
|
+
console.log('Result:', JSON.stringify(result, null, 2));
|
|
23
|
+
} catch (err) {
|
|
24
|
+
console.log('Error:', err);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
run().catch(console.error);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { authenticatedLndGrpc } = require('../index.js');
|
|
3
|
+
const { decodeAssetPayReq } = require('../lnd_methods/offchain'); // Our custom method
|
|
4
|
+
|
|
5
|
+
const LND_MACAROON = "0201047461706402d001030a10234023c36f0935c6b7c16a87731ce9a61201301a180a09616464726573736573120472656164120577726974651a150a06617373657473120472656164120577726974651a170a086368616e6e656c73120472656164120577726974651a150a066461656d6f6e120472656164120577726974651a130a046d696e74120472656164120577726974651a150a0670726f6f6673120472656164120577726974651a120a03726671120472656164120577726974651a170a08756e697665727365120472656164120577726974650000062043a24238843d0d368e4ebff0b40c6c470410ae6a0b8e494082a4d0275a682fac";
|
|
6
|
+
const LND_SOCKET = "127.0.0.1:8443";
|
|
7
|
+
const LND_TLS_CERT_PATH = "/Users/jim/.polar/networks/1/volumes/litd/alice/lit/tls.cert";
|
|
8
|
+
|
|
9
|
+
// Dave's 3-hop invoice
|
|
10
|
+
const daveInvoice = 'lnbcrt50u1p5eana8pp52nzxmlynxp9p702l29wsaxz7wlqpuvcvwwvhh0uuhgqnr3tgvgwsdqqcqzzsxqrrssrzjq0cejmct3flggm7d40m3un7whtfqpvpmzz9ycc3wdtz3ksj2f26aea2uffn04skg8gqqqqlgqqqqqqgq2qsp5nxlk85rnkph60ggvkf5udzfh3v0qpws2x48nmvtcya7aqqwz43ps9qxpqysgqq9jnm60aq5pvgp6x5xp6utx939z2f4mp3t5se2qzyw9ymppc93qyv9yz2nx29nv3l06c5jl8t2t7zgut5zh7v2nqzvsfz9u4590694qpne2jr9';
|
|
11
|
+
const assetId = "c5a9dd2243daa3ef0b491c446e54d1d262b96bf95107cb883ecdee43989efd64";
|
|
12
|
+
|
|
13
|
+
async function run() {
|
|
14
|
+
const base64Cert = fs.readFileSync(LND_TLS_CERT_PATH).toString("base64");
|
|
15
|
+
const { lnd: tpr } = authenticatedLndGrpc({
|
|
16
|
+
cert: base64Cert,
|
|
17
|
+
macaroon: LND_MACAROON,
|
|
18
|
+
socket: LND_SOCKET,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
console.log('Decoding Dave invoice using tapd DecodeAssetPayReq...');
|
|
22
|
+
try {
|
|
23
|
+
const res = await decodeAssetPayReq({
|
|
24
|
+
tpr,
|
|
25
|
+
asset_id: assetId,
|
|
26
|
+
pay_req_string: daveInvoice
|
|
27
|
+
});
|
|
28
|
+
console.log(JSON.stringify(res, null, 2));
|
|
29
|
+
} catch(err) {
|
|
30
|
+
console.log(err);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
run().catch(console.error);
|
package/test.js
CHANGED
|
@@ -14,6 +14,7 @@ const fs = require("fs");
|
|
|
14
14
|
const crypto = require("crypto");
|
|
15
15
|
const { createHash } = require("crypto");
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
// const dayjs = require("dayjs");
|
|
18
19
|
/* const LND_TLS_CERT =
|
|
19
20
|
"/Users/wjl/Documents/gamichi/2024/astra/volumes/server/tls.cert";
|
|
@@ -72,14 +73,19 @@ const getPriceOrcaleMetadata = async ({
|
|
|
72
73
|
|
|
73
74
|
const messageToSign = Object.values(price_oracle_metadata).join("");
|
|
74
75
|
const { signature } = await signMessage({ lnd, message: messageToSign });
|
|
75
|
-
const public_key =
|
|
76
|
-
"02607b201503d39fe886cc13637f4dcfa45ea6a83d6b1f5ab8ce780e1157af1718";
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
|
|
78
|
+
const { public_key } = await getIdentity({ lnd });
|
|
79
|
+
|
|
80
|
+
const ret = {
|
|
79
81
|
...price_oracle_metadata,
|
|
80
82
|
public_key,
|
|
81
|
-
sign: signature
|
|
82
|
-
|
|
83
|
+
sign: signature
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...ret,
|
|
88
|
+
raw_data: JSON.stringify(ret)
|
|
83
89
|
};
|
|
84
90
|
};
|
|
85
91
|
|
|
@@ -143,14 +149,23 @@ const payWithTpr = async (invoice, assetId) => {
|
|
|
143
149
|
} */
|
|
144
150
|
const peerPubkey = "03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3";
|
|
145
151
|
|
|
146
|
-
|
|
147
|
-
const decodedReq = await decodeAssetPayReq({ lnd, request: invoice }).then(res => res.destination);
|
|
148
152
|
const priceOracleMetadata = await getPriceOrcaleMetadata({
|
|
149
153
|
assetId,
|
|
150
|
-
transaction_type: "
|
|
151
|
-
amount:
|
|
152
|
-
request_id:
|
|
154
|
+
transaction_type: "0",
|
|
155
|
+
amount: '1000',
|
|
156
|
+
request_id: "073e00ff6bb64fa787189f662d0b9180e43eee4d320603b897fe4cfafb70c018",
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const decodedReq = await decodeAssetPayReq({ asset_id: assetId, tpr, pay_req_string: invoice, price_oracle_metadata: priceOracleMetadata.raw_data }).catch((e) => {
|
|
160
|
+
console.log("error", e.message);
|
|
153
161
|
});
|
|
162
|
+
|
|
163
|
+
console.log("🚀 ~ decodedReq:", decodedReq)
|
|
164
|
+
|
|
165
|
+
return;
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
console.log("🚀 ~ priceOracleMetadata:", priceOracleMetadata.raw_data)
|
|
154
169
|
const retPay = await payTaprootInvoice({
|
|
155
170
|
lnd: lnd,
|
|
156
171
|
tpr: tpr,
|
|
@@ -159,7 +174,7 @@ const payWithTpr = async (invoice, assetId) => {
|
|
|
159
174
|
peer_pubkey: peerPubkey,
|
|
160
175
|
payment_request: {
|
|
161
176
|
payment_request: invoice,
|
|
162
|
-
fee_limit_sat:
|
|
177
|
+
fee_limit_sat: 100,
|
|
163
178
|
allow_self_payment: true,
|
|
164
179
|
timeout_seconds: 60 * 5,
|
|
165
180
|
outgoing_chan_id: "118422899869679616",
|
|
@@ -167,7 +182,7 @@ const payWithTpr = async (invoice, assetId) => {
|
|
|
167
182
|
price_oracle_metadata: priceOracleMetadata.raw_data,
|
|
168
183
|
}).catch((e) => {
|
|
169
184
|
console.log("error", e.message);
|
|
170
|
-
|
|
185
|
+
|
|
171
186
|
});
|
|
172
187
|
console.log("ret", retPay);
|
|
173
188
|
|
|
@@ -256,11 +271,11 @@ const addTapdInvoice = async () => {
|
|
|
256
271
|
const ret = await createInvoice({
|
|
257
272
|
lnd,
|
|
258
273
|
tpr,
|
|
259
|
-
mtokens:
|
|
274
|
+
mtokens: 1000,
|
|
260
275
|
// expires_at:'1764839000',
|
|
261
276
|
peer_pubkey:"03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3",
|
|
262
277
|
asset_id: assetId,
|
|
263
|
-
price_oracle_metadata:
|
|
278
|
+
price_oracle_metadata: price_oracle_metadata.raw_data,
|
|
264
279
|
secret: preimage,
|
|
265
280
|
|
|
266
281
|
}).catch((e) => {
|
|
@@ -270,7 +285,7 @@ const addTapdInvoice = async () => {
|
|
|
270
285
|
};
|
|
271
286
|
|
|
272
287
|
const decodeTapdInvoice = async()=>{
|
|
273
|
-
const invoice ='
|
|
288
|
+
const invoice ='lnbcrt113794960p1p55eu9mpp5qulqplmtke860pccnanz6zu3srjramjdxgrq8wyhlex047mscqvqdqqcqzzsxqr23srzjqwey5jlez8lay6kp6hjly3q28shkja8yejza9m65u9lwd5m3wsea8a802ktvdptv8sqqqqlgqqqqqqgq2qsp54eq4dtr2pqp24qx5cxm0yw4xadluwj4kkf6r4fuwyjj4wje5nnwq9qxpqysgqyq37rkxh3l9p77796zr24q4p4jv6ftr4hv6hr2t2z695wn8uuu7zmqm3nskdfnk0t788wcxkxr03astatvm4e4pyqnpn3ffc8603z4cpu2glhj'
|
|
274
289
|
const ret = await decodeAssetPayReq({
|
|
275
290
|
asset_id: assetId,
|
|
276
291
|
pay_req_string: invoice,
|
|
@@ -421,16 +436,16 @@ const getBestLndChannel = async (asset) => {
|
|
|
421
436
|
};
|
|
422
437
|
|
|
423
438
|
const test = async () => {
|
|
424
|
-
const ret = await getIdentity({ lnd });
|
|
425
|
-
console.log("🚀 ~ test ~ ret:", ret)
|
|
426
|
-
//getBestLndChannel({assetId, isBTC: false})
|
|
439
|
+
/* const ret = await getIdentity({ lnd });
|
|
440
|
+
console.log("🚀 ~ test ~ ret:", ret) */
|
|
441
|
+
// getBestLndChannel({assetId, isBTC: false})
|
|
427
442
|
/* const sub = subscribeToInvoices({ lnd });
|
|
428
443
|
sub.on("invoice_updated",async(invoice)=>{
|
|
429
444
|
console.log('invoice',invoice)
|
|
430
445
|
}) */
|
|
431
446
|
//await addTapdInvoice();
|
|
432
447
|
//await decodeTapdInvoice();
|
|
433
|
-
|
|
448
|
+
//await listChannels();
|
|
434
449
|
// const ret = await getBestLndChannel({
|
|
435
450
|
// assetId: assetId,
|
|
436
451
|
// isBTC: false,
|
|
@@ -457,6 +472,8 @@ const test = async () => {
|
|
|
457
472
|
sub.on("payment", async (payment) => {
|
|
458
473
|
console.log('payment',payment)
|
|
459
474
|
}); */
|
|
475
|
+
const invoice ="lnbcrt113794960p1p55eu9mpp5qulqplmtke860pccnanz6zu3srjramjdxgrq8wyhlex047mscqvqdqqcqzzsxqr23srzjqwey5jlez8lay6kp6hjly3q28shkja8yejza9m65u9lwd5m3wsea8a802ktvdptv8sqqqqlgqqqqqqgq2qsp54eq4dtr2pqp24qx5cxm0yw4xadluwj4kkf6r4fuwyjj4wje5nnwq9qxpqysgqyq37rkxh3l9p77796zr24q4p4jv6ftr4hv6hr2t2z695wn8uuu7zmqm3nskdfnk0t788wcxkxr03astatvm4e4pyqnpn3ffc8603z4cpu2glhj"
|
|
476
|
+
await payWithTpr(invoice,assetId)
|
|
460
477
|
|
|
461
478
|
};
|
|
462
479
|
test();
|