astra-lightning 1.1.4 → 1.1.6
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.
|
@@ -20,6 +20,10 @@ const { parse } = Date;
|
|
|
20
20
|
const { round } = Math;
|
|
21
21
|
const tokensAsMtok = (tokens) => (BigInt(tokens) * BigInt(1e3)).toString();
|
|
22
22
|
const type = "default";
|
|
23
|
+
const isDuplicateInvoiceError = (err = {}) => {
|
|
24
|
+
const message = err.details || err.message || String();
|
|
25
|
+
return typeof message === "string" && message.includes(invoiceExistsError);
|
|
26
|
+
};
|
|
23
27
|
|
|
24
28
|
/** Create a Lightning invoice.
|
|
25
29
|
|
|
@@ -81,7 +85,10 @@ module.exports = (args, cbk) => {
|
|
|
81
85
|
|
|
82
86
|
// Check arguments
|
|
83
87
|
validate: (cbk) => {
|
|
84
|
-
if (
|
|
88
|
+
if (
|
|
89
|
+
!!args.expires_at &&
|
|
90
|
+
Math.floor(Date.now() / 1000) > Number(args.expires_at)
|
|
91
|
+
) {
|
|
85
92
|
return cbk([400, "ExpectedFutureDateForInvoiceExpiration"]);
|
|
86
93
|
}
|
|
87
94
|
|
|
@@ -163,9 +170,10 @@ module.exports = (args, cbk) => {
|
|
|
163
170
|
({ addAddress, hints, mtokens, preimage }, cbk) => {
|
|
164
171
|
const fallbackAddress = !addAddress ? String() : addAddress.address;
|
|
165
172
|
const createdAt = new Date();
|
|
166
|
-
const expireAt = !args.expires_at ? null :
|
|
167
|
-
|
|
173
|
+
const expireAt = !args.expires_at ? null : Math.floor(args.expires_at*msPerSec);
|
|
174
|
+
|
|
168
175
|
const expiryMs = !expireAt ? null : expireAt - createdAt.getTime();
|
|
176
|
+
|
|
169
177
|
if (!args.asset_id) {
|
|
170
178
|
return args.lnd.default.addInvoice(
|
|
171
179
|
{
|
|
@@ -183,7 +191,7 @@ module.exports = (args, cbk) => {
|
|
|
183
191
|
value_msat: mtokens,
|
|
184
192
|
},
|
|
185
193
|
(err, response) => {
|
|
186
|
-
if (!!err && err
|
|
194
|
+
if (!!err && isDuplicateInvoiceError(err)) {
|
|
187
195
|
return cbk([409, "InvoiceWithGivenHashAlreadyExists"]);
|
|
188
196
|
}
|
|
189
197
|
|
|
@@ -228,6 +236,10 @@ module.exports = (args, cbk) => {
|
|
|
228
236
|
}
|
|
229
237
|
);
|
|
230
238
|
} else {
|
|
239
|
+
const expiry = !expiryMs
|
|
240
|
+
? defaultExpirySec
|
|
241
|
+
: round(expiryMs / msPerSec)
|
|
242
|
+
|
|
231
243
|
return args.tpr.taproot_asset_channels.addInvoice(
|
|
232
244
|
{
|
|
233
245
|
asset_id: hexAsBuffer(args.asset_id),
|
|
@@ -236,9 +248,7 @@ module.exports = (args, cbk) => {
|
|
|
236
248
|
invoice_request: {
|
|
237
249
|
cltv_expiry: !args.cltv_delta ? undefined : args.cltv_delta,
|
|
238
250
|
description_hash: hexAsBuffer(args.description_hash),
|
|
239
|
-
expiry:
|
|
240
|
-
? defaultExpirySec
|
|
241
|
-
: round(expiryMs / msPerSec),
|
|
251
|
+
expiry: expiry,
|
|
242
252
|
fallback_addr: fallbackAddress,
|
|
243
253
|
is_blinded: !!args.is_encrypting_routes,
|
|
244
254
|
memo: args.description,
|
|
@@ -246,12 +256,13 @@ module.exports = (args, cbk) => {
|
|
|
246
256
|
r_preimage: preimage || undefined,
|
|
247
257
|
route_hints: hints || undefined,
|
|
248
258
|
},
|
|
259
|
+
group_key: args.group_key ? hexAsBuffer(args.group_key) : undefined,
|
|
260
|
+
price_oracle_metadata: args.price_oracle_metadata,
|
|
249
261
|
},
|
|
250
262
|
(err, response) => {
|
|
251
|
-
if (!!err && err
|
|
263
|
+
if (!!err && isDuplicateInvoiceError(err)) {
|
|
252
264
|
return cbk([409, "InvoiceWithGivenHashAlreadyExists"]);
|
|
253
265
|
}
|
|
254
|
-
|
|
255
266
|
if (!!err) {
|
|
256
267
|
return cbk([503, "AddInvoiceError", { err }]);
|
|
257
268
|
}
|
|
@@ -7,6 +7,8 @@ export type PaymentTaprootInvoiceArgs = AuthenticatedLightningArgs<{
|
|
|
7
7
|
asset_id: string;
|
|
8
8
|
asset_amount: number;
|
|
9
9
|
peer_pubkey: string;
|
|
10
|
+
price_oracle_metadata?: string;
|
|
11
|
+
group_key?: string;
|
|
10
12
|
payment_request: {
|
|
11
13
|
payment_request: string;
|
|
12
14
|
fee_limit_sat: number;
|
|
@@ -43,6 +43,8 @@ module.exports = (args) => {
|
|
|
43
43
|
asset_amount: args.asset_amount,
|
|
44
44
|
peer_pubkey: hexAsBuffer(args.peer_pubkey),
|
|
45
45
|
payment_request: args.payment_request,
|
|
46
|
+
price_oracle_metadata: args.price_oracle_metadata ? args.price_oracle_metadata : undefined,
|
|
47
|
+
group_key: args.group_key ? hexAsBuffer(args.group_key) : undefined,
|
|
46
48
|
}
|
|
47
49
|
const sub = args.tpr.taproot_asset_channels.sendPayment(callRequest);
|
|
48
50
|
const ret = {
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -5,8 +5,15 @@ const {
|
|
|
5
5
|
decodePaymentRequest,
|
|
6
6
|
decodeAssetPayReq,
|
|
7
7
|
createInvoice,
|
|
8
|
+
signMessage,
|
|
9
|
+
getIdentity,
|
|
10
|
+
subscribeToInvoices,
|
|
11
|
+
subscribeToPastPayments
|
|
8
12
|
} = require("./index.js");
|
|
9
13
|
const fs = require("fs");
|
|
14
|
+
const crypto = require("crypto");
|
|
15
|
+
const { createHash } = require("crypto");
|
|
16
|
+
|
|
10
17
|
// const dayjs = require("dayjs");
|
|
11
18
|
/* const LND_TLS_CERT =
|
|
12
19
|
"/Users/wjl/Documents/gamichi/2024/astra/volumes/server/tls.cert";
|
|
@@ -22,17 +29,17 @@ const LND_SOCKET = "54.92.19.81:10109"; */
|
|
|
22
29
|
// const invoice =
|
|
23
30
|
// "lnbcrt10u1p5q3r0zpp50v0asn72aav354e27cals6l7j76sln0pzzvxktgur2wmlkf44mfqdy0f3hxv6fmv9ehxet5f9zr5dtzvscnywtyx56rjcnyxcuxxctyxc6xvvnrxfjxyvf5xymnxvnpx5erxef5x56rvcf58ymrvvnrxvunqefcvvcngv3ex3skzdm98q6rkctdda6kuap6xycrqwscqzzsxqrrssrzjqg3zz9zaagxqxan9fqzr6k7yvf900uf26m0z7c2g0rf55raupqclpakyc0a4gzq2v5qqqqlgqqqqqqgq2qsp58qmfwjwdrvr9dzjs2esms3cpvvgff3g4hsunszne3v7wszwcq62s9qxpqysgqscq2e3sqa0pfe5yzjdnp8q4temjazdw6y77c49tpvnhz0d4kjux92tw3gy9vvrh68qqef594frdp2uqhvwjy0sd7ezdcanvlln2rusgpg5w96t";
|
|
24
31
|
|
|
25
|
-
const LND_SOCKET = "127.0.0.1:8444";
|
|
26
32
|
const LND_MACAROON =
|
|
27
|
-
"
|
|
33
|
+
"0201036c6e6402f801030a1020a1bf5a962e198f49d7d0cb5dacb7221201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e6572617465120472656164000006207db76ec2a58ad259d4a4a5d3c4cff4bbd48b8667dee0cfdbf7e0299303fae9c6";
|
|
28
34
|
const LND_TPROOT_ASSET_MACAROON =
|
|
29
|
-
"
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const invoice =
|
|
35
|
+
"0201047461706402d001030a1027a1bf5a962e198f49d7d0cb5dacb7221201301a180a09616464726573736573120472656164120577726974651a150a06617373657473120472656164120577726974651a170a086368616e6e656c73120472656164120577726974651a150a066461656d6f6e120472656164120577726974651a130a046d696e74120472656164120577726974651a150a0670726f6f6673120472656164120577726974651a120a03726671120472656164120577726974651a170a08756e69766572736512047265616412057772697465000006201bcecd78be5724f8127277b4b68fb65ce6cf2b502585d20318da22b3d473a20e";
|
|
36
|
+
const LND_SOCKET = "regtest.lnfi.network:10019";
|
|
37
|
+
const LND_TLS_CERT =
|
|
38
|
+
"/Users/jim/Documents/gamichi/2024/astra/packages/server/volumes/tls.cert";
|
|
39
|
+
const base64Cert = fs.readFileSync(LND_TLS_CERT).toString("base64");
|
|
35
40
|
"";
|
|
41
|
+
const assetId ="f7ac99f2c068f1157c787012f50cb043437505c309c6d8685e135cd8481b1e9d";
|
|
42
|
+
|
|
36
43
|
|
|
37
44
|
const { lnd } = authenticatedLndGrpc({
|
|
38
45
|
cert: base64Cert,
|
|
@@ -45,6 +52,37 @@ const { lnd: tpr } = authenticatedLndGrpc({
|
|
|
45
52
|
socket: LND_SOCKET,
|
|
46
53
|
});
|
|
47
54
|
|
|
55
|
+
const getPriceOrcaleMetadata = async ({
|
|
56
|
+
assetId,
|
|
57
|
+
transaction_type = "0",
|
|
58
|
+
amount = "1000",
|
|
59
|
+
request_id,
|
|
60
|
+
}) => {
|
|
61
|
+
if (!request_id) {
|
|
62
|
+
throw new Error("request_id is required to build price_oracle_metadata");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const price_oracle_metadata = {
|
|
66
|
+
type: "bridge",
|
|
67
|
+
asset_id: assetId,
|
|
68
|
+
transaction_type,
|
|
69
|
+
amount,
|
|
70
|
+
request_id,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const messageToSign = Object.values(price_oracle_metadata).join("");
|
|
74
|
+
const { signature } = await signMessage({ lnd, message: messageToSign });
|
|
75
|
+
const public_key =
|
|
76
|
+
"02607b201503d39fe886cc13637f4dcfa45ea6a83d6b1f5ab8ce780e1157af1718";
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
...price_oracle_metadata,
|
|
80
|
+
public_key,
|
|
81
|
+
sign: signature,
|
|
82
|
+
raw_data: JSON.stringify(price_oracle_metadata)
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
48
86
|
const payWithTpr = async (invoice, assetId) => {
|
|
49
87
|
// const provider = new ethers.JsonRpcProvider('https://eth-sepolia.g.alchemy.com/v2/ClvXGqSMvZ6nEb_G5ekJGsZwNdsp72oz');
|
|
50
88
|
// const lspSigner = new ethers.Wallet('dd5862c69e641fb052092d34724ce62764186abf87474656f2b2149684dca754', provider);
|
|
@@ -57,7 +95,7 @@ const payWithTpr = async (invoice, assetId) => {
|
|
|
57
95
|
// request: invoice
|
|
58
96
|
// })
|
|
59
97
|
|
|
60
|
-
const ret = await getChannels({ lnd }).catch((error) => console.log(error));
|
|
98
|
+
/* const ret = await getChannels({ lnd }).catch((error) => console.log(error));
|
|
61
99
|
|
|
62
100
|
const filterChannels = ret.channels.filter(
|
|
63
101
|
(channel) =>
|
|
@@ -102,23 +140,34 @@ const payWithTpr = async (invoice, assetId) => {
|
|
|
102
140
|
throw new Error(
|
|
103
141
|
`channelId: ${maxLocalBalanceChannel.channel_id} not enough balance`
|
|
104
142
|
);
|
|
105
|
-
}
|
|
106
|
-
const peerPubkey =
|
|
143
|
+
} */
|
|
144
|
+
const peerPubkey = "03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3";
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
const decodedReq = await decodeAssetPayReq({ lnd, request: invoice }).then(res => res.destination);
|
|
148
|
+
const priceOracleMetadata = await getPriceOrcaleMetadata({
|
|
149
|
+
assetId,
|
|
150
|
+
transaction_type: "1",
|
|
151
|
+
amount: 0,
|
|
152
|
+
request_id: decodedReq.pay_req.payment_hash,
|
|
153
|
+
});
|
|
107
154
|
const retPay = await payTaprootInvoice({
|
|
108
155
|
lnd: lnd,
|
|
109
156
|
tpr: tpr,
|
|
110
157
|
asset_id: assetId,
|
|
111
|
-
asset_amount:
|
|
158
|
+
asset_amount: decodedReq.asset_amount,
|
|
112
159
|
peer_pubkey: peerPubkey,
|
|
113
160
|
payment_request: {
|
|
114
161
|
payment_request: invoice,
|
|
115
162
|
fee_limit_sat: 1000,
|
|
116
163
|
allow_self_payment: true,
|
|
117
164
|
timeout_seconds: 60 * 5,
|
|
118
|
-
outgoing_chan_id:
|
|
165
|
+
outgoing_chan_id: "118422899869679616",
|
|
119
166
|
},
|
|
167
|
+
price_oracle_metadata: priceOracleMetadata.raw_data,
|
|
120
168
|
}).catch((e) => {
|
|
121
169
|
console.log("error", e.message);
|
|
170
|
+
throw e;
|
|
122
171
|
});
|
|
123
172
|
console.log("ret", retPay);
|
|
124
173
|
|
|
@@ -175,20 +224,53 @@ const payWithTpr = async (invoice, assetId) => {
|
|
|
175
224
|
// }
|
|
176
225
|
// queryBalance();
|
|
177
226
|
|
|
227
|
+
|
|
228
|
+
|
|
178
229
|
const addTapdInvoice = async () => {
|
|
230
|
+
const secret = crypto.randomBytes(32);
|
|
231
|
+
const preimage = secret.toString("hex");
|
|
232
|
+
const hash = createHash("sha256").update(secret).digest("hex");
|
|
233
|
+
|
|
234
|
+
/*
|
|
235
|
+
"sign": "lncli.signmessage(type + asset_id+ transaction_type+ amount + request_id )"
|
|
236
|
+
{
|
|
237
|
+
"type": "bridge",
|
|
238
|
+
"asset_id": "9fe1643dd1ae81208fde67d1bce2b3a3a6cd158a868d3c6774eb075b4f032004",
|
|
239
|
+
"transaction_type": "0", //0买 1卖
|
|
240
|
+
"amount": "4100",
|
|
241
|
+
"request_id": "hash(preimage)",
|
|
242
|
+
"public_key": "0261f6cc4cdc3b59c9910badebd6d0c34f7f9357320a349af906ecf750dda0bcc4",
|
|
243
|
+
"sign": "lncli.signmessage(type + asset_id+ transaction_type+ amount + request_id )"
|
|
244
|
+
}
|
|
245
|
+
*/
|
|
246
|
+
const price_oracle_metadata = await getPriceOrcaleMetadata({
|
|
247
|
+
assetId,
|
|
248
|
+
transaction_type: "0",
|
|
249
|
+
amount: "1000",
|
|
250
|
+
request_id: hash,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
console.log("price_oracle_metadata", price_oracle_metadata);
|
|
254
|
+
|
|
255
|
+
//return;
|
|
179
256
|
const ret = await createInvoice({
|
|
180
257
|
lnd,
|
|
181
258
|
tpr,
|
|
182
|
-
mtokens:
|
|
259
|
+
mtokens: 1000000,
|
|
260
|
+
// expires_at:'1764839000',
|
|
261
|
+
peer_pubkey:"03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3",
|
|
183
262
|
asset_id: assetId,
|
|
263
|
+
price_oracle_metadata: JSON.stringify(price_oracle_metadata),
|
|
264
|
+
secret: preimage,
|
|
265
|
+
|
|
184
266
|
}).catch((e) => {
|
|
185
|
-
console.error("Failed to create invoice:", e
|
|
267
|
+
console.error("Failed to create invoice:", e);
|
|
186
268
|
});
|
|
187
269
|
console.log("🚀 ~ addTapdInvoice ~ ret:", ret);
|
|
188
270
|
};
|
|
189
271
|
|
|
190
272
|
const decodeTapdInvoice = async()=>{
|
|
191
|
-
const invoice ='
|
|
273
|
+
const invoice ='lnbcrt114742690p1p55hxxjpp584aulkj02vhaqujfv0lv5dtyuw4vrnk67uvx77q4y20md22sxz3sdqqcqzzsxqr23srzjqf7j7xl8rhpycc932pcy382w7f6d664vydks93nuwmtfxh00hft2da0glksvd4c3acqqqqlgqqqqqqgq2qsp5duc6ezxqyllkxqvevmr34d852nplfknk3jc2dvwktv2gh3pdrxus9qxpqysgqc67uh6vl2epzj32s0qf86v7hpygs3tps3ejy9uca78p2w0dgfjnzshlxpfmwws6xwecw0c7z47jvuglywhqg4tq260h7tv30sxkvxqgqpeufpe'
|
|
192
274
|
const ret = await decodeAssetPayReq({
|
|
193
275
|
asset_id: assetId,
|
|
194
276
|
pay_req_string: invoice,
|
|
@@ -210,7 +292,7 @@ const getBestLndChannel = async (asset) => {
|
|
|
210
292
|
return {channels: []};
|
|
211
293
|
});
|
|
212
294
|
|
|
213
|
-
|
|
295
|
+
|
|
214
296
|
|
|
215
297
|
let filterChannels = [];
|
|
216
298
|
let sortTprChannels = [];
|
|
@@ -257,6 +339,8 @@ const getBestLndChannel = async (asset) => {
|
|
|
257
339
|
return hasLocal || hasFunding || hasRemote;
|
|
258
340
|
});
|
|
259
341
|
|
|
342
|
+
console.log('filterChannels',filterChannels)
|
|
343
|
+
|
|
260
344
|
|
|
261
345
|
sortTprChannels = filterChannels.sort((a, b) => {
|
|
262
346
|
let aData;
|
|
@@ -337,7 +421,14 @@ const getBestLndChannel = async (asset) => {
|
|
|
337
421
|
};
|
|
338
422
|
|
|
339
423
|
const test = async () => {
|
|
340
|
-
await
|
|
424
|
+
const ret = await getIdentity({ lnd });
|
|
425
|
+
console.log("🚀 ~ test ~ ret:", ret)
|
|
426
|
+
//getBestLndChannel({assetId, isBTC: false})
|
|
427
|
+
/* const sub = subscribeToInvoices({ lnd });
|
|
428
|
+
sub.on("invoice_updated",async(invoice)=>{
|
|
429
|
+
console.log('invoice',invoice)
|
|
430
|
+
}) */
|
|
431
|
+
//await addTapdInvoice();
|
|
341
432
|
//await decodeTapdInvoice();
|
|
342
433
|
//await listChannels();
|
|
343
434
|
// const ret = await getBestLndChannel({
|
|
@@ -361,6 +452,11 @@ const test = async () => {
|
|
|
361
452
|
// },
|
|
362
453
|
// });
|
|
363
454
|
// console.log("🚀 ~ test ~ retPay:", retPay)
|
|
455
|
+
|
|
456
|
+
/* const sub = subscribeToPastPayments({ lnd });
|
|
457
|
+
sub.on("payment", async (payment) => {
|
|
458
|
+
console.log('payment',payment)
|
|
459
|
+
}); */
|
|
364
460
|
|
|
365
461
|
};
|
|
366
462
|
test();
|