UNPKG

invoices

Version:

Methods for working with BOLT 11 payment requests

327 lines (309 loc) 13.5 kB
const {sign} = require('tiny-secp256k1'); const {equal} = require('node:assert').strict; const strictSame = require('node:assert').strict.deepStrictEqual; const test = require('node:test'); const {throws} = require('node:assert').strict; const {createSignedRequest} = require('./../../'); const {createUnsignedRequest} = require('./../../'); const {parsePaymentRequest} = require('./../../'); const wordsAsBuffer = require('./../../bolt11/words_as_buffer'); const bufFromHex = hex => Buffer.from(hex, 'hex'); const tests = [ { args: { created_at: '2017-06-01T10:57:38.000Z', description_hash: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1', id: '0001020304050607080900010203040506070809000102030405060708090102', mtokens: '2000000000', network: 'bitcoin', }, description: 'Test creating a regular unsigned request', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404082e1a1c92db7b3f161a001b7689049eea2701b46f8db7513629edf2408fac7eaedc60800', hash: 'b6025e8a10539dddbcbe6840a9650707ae3f147b8dcfda338561ada710508916', hrp: 'lnbc20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { created_at: '2017-06-01T10:57:38.000Z', description: 'Please consider supporting this project', id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', }, description: 'Test creating a donation payment request', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404081a1fa83632b0b9b29031b7b739b4b232b91039bab83837b93a34b733903a3434b990383937b532b1ba0', hash: 'c3d4e83f646fa79a393d75277b1d858db1d1f7ab7137dcb7835db2ecd518e1c9', hrp: 'lnbc', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { created_at: '2017-06-01T10:57:38.000Z', description: '', id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', }, description: 'Test creating an empty description request', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404081a000', hash: 'a7c24a7ac6369ea6b25ca3534cba0e5971d7b3ac93a2cb74e620b6eac52be9d9', hrp: 'lnbc', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { created_at: '2017-06-01T10:57:38.000Z', description: '1 cup coffee', expires_at: '2017-06-01T10:58:38.000Z', id: '0001020304050607080900010203040506070809000102030405060708090102', mtokens: '250000000', network: 'bitcoin', }, description: 'Payment request with expiration time', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404080c01078d050c4818dd5c0818dbd9999959400', hash: '41545c21535123568d875cf108983e97323857e05d302e8c0c8091540f496b6e', hrp: 'lnbc2500u', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { created_at: '2017-06-01T10:57:38.000Z', description: 'ナンセンス 1杯', expires_at: '2017-06-01T10:58:38.000Z', id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', tokens: 250000, }, description: 'Payment request with utf8 characters in description', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404080c01078d0838e0e2b8e0ecf8e0aef8e0ecf8e0ae480c79a76bc', hash: 'a66929bfdba1ef8480f41f0a509646d100971a1b1ef074ecc2ad283ef872fb78', hrp: 'lnbc2500u', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { created_at: '2017-06-01T10:57:38.000Z', description_hash: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1', id: '0001020304050607080900010203040506070809000102030405060708090102', mtokens: '2000000000', network: 'bitcoin', }, description: 'Payment request with hash of list of items', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404082e1a1c92db7b3f161a001b7689049eea2701b46f8db7513629edf2408fac7eaedc60800', hash: 'b6025e8a10539dddbcbe6840a9650707ae3f147b8dcfda338561ada710508916', hrp: 'lnbc20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { chain_addresses: ['mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'], created_at: '2017-06-01T10:57:38.000Z', description_hash: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1', id: '0001020304050607080900010203040506070809000102030405060708090102', mtokens: '2000000000', network: 'testnet', }, description: 'Payment request with a fallback address', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404081210c4c5cad5953d9a0f23ec51a5674d1f38c0f2b9329ee1a1c92db7b3f161a001b7689049eea2701b46f8db7513629edf2408fac7eaedc6080', hash: '8a70928b442c583b3c2206bd72c2edf3bbe514444134285d6abbc6e98c552d92', hrp: 'lntb20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { chain_addresses: ['1RustyRX2oai4EYYDpQGWvEL62BBGqN9T'], created_at: '2017-06-01T10:57:38.000Z', description_hash: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1', id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', routes: [[ { public_key: '029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255', }, { base_fee_mtokens: '1', channel: '66051x263430x1800', cltv_delta: 3, fee_rate: 20, public_key: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', }, ]], tokens: 2000000, }, description: 'Payment request with routing hints', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404080629014f01d480dc2a9a7f8f49621e3a218fbe7390230307e7bd4ae1bf0a47bc63b92a8081018202830384000000008000000a0001890862096c3efb83d41b9328488c99880c9b8ac9b23d1370d0e496dbd9f8b0d000dbb44824f751380da37c6dba89b14f6f92047d63f576e3040', hash: '215f17ac50e01dbcce070aa15d9ebd29088c7e7e37eb8f6ae071770ca40dd47b', hrp: 'lnbc20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { chain_addresses: ['3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'], created_at: '2017-06-01T10:57:38.000Z', description_hash: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1', id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', tokens: 2000000, }, description: 'Payment request with p2sh', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404081210ca3d5558ee6867cc870847a6e7ce337da1ba81e116e1a1c92db7b3f161a001b7689049eea2701b46f8db7513629edf2408fac7eaedc6080', hash: 'aff3372fd3da5db4d6cc7cd757c5ad2804ab76f7eb68a79617e4f9edf329cdb3', hrp: 'lnbc20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { chain_addresses: ['bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'], created_at: '2017-06-01T10:57:38.000Z', description_hash: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1', id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', tokens: 2000000, }, description: 'Payment request with p2wpkh', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c20240408121081d479dba066465b515250711746ce8c8fc50cef5ae1a1c92db7b3f161a001b7689049eea2701b46f8db7513629edf2408fac7eaedc6080', hash: '53c4634f904ae9e1888e5158d6b7e352c4352cb2e43bf60019352baa471551cd', hrp: 'lnbc20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { chain_addresses: ['bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'], created_at: '2017-06-01T10:57:38.000Z', description_hash: '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1', id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', tokens: 2000000, }, description: 'Payment request with p2wsh', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c20240408121a80618c50f0531459a012f46480cd5b684db26159e335349e86e318ca581240c9882e1a1c92db7b3f161a001b7689049eea2701b46f8db7513629edf2408fac7eaedc60800', hash: '827b34dedbcebfbead318c8ca5d0fdeffb47e79261035980b059dcf66ae83ade', hrp: 'lnbc20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, { args: { created_at: '2017-06-01T10:57:38.000Z', description: 'coffee beans', features: [ { bit: 15, is_required: false, type: 'payment_identifier', }, { bit: 99, is_required: false, type: undefined, }, ], id: '0001020304050607080900010203040506070809000102030405060708090102', network: 'bitcoin', payment: '1111111111111111111111111111111111111111111111111111111111111111', tokens: 2000000, }, description: 'With features and payment identifier', expected: { data: '0b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404080a0a40000000000000000000040003414636f66666565206265616e730806822222222222222222222222222222222222222222222222222222222222222220', hash: 'ca79ddcfb01fc3232cf784075742a259afa0d3506c0db278b95175154a89bda5', hrp: 'lnbc20m', }, verify: { destination: '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad', private_key: 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734', }, }, ]; tests.forEach(({args, description, expected, verify}) => { return test(description, (t, end) => { const {hash, hrp, tags} = createUnsignedRequest(args); const data = wordsAsBuffer({words: tags}).toString('hex'); equal(data, expected.data, 'Tags calculated for payment request'); equal(hash, expected.hash, 'Hash calculated for payment request'); equal(hrp, expected.hrp, 'Hrp calculated for payment request'); const signature = sign(bufFromHex(hash), bufFromHex(verify.private_key)); const {request} = createSignedRequest({ hrp, tags, destination: verify.destination, signature: Buffer.from(signature).toString('hex'), }); const parsed = parsePaymentRequest({request}); strictSame(parsed.chain_addresses, args.chain_addresses, 'Fallbacks'); equal(parsed.cltv_delta, args.cltv_delta || 18, 'Request cltv expected'); equal(parsed.created_at, args.created_at, 'Request create_at is expected'); equal(parsed.description, args.description, 'Req description expected'); equal(parsed.description_hash, args.description_hash, 'Got Desc hash'); equal(parsed.destination, verify.destination, 'Destination key expected'); if (!!args.features) { strictSame(parsed.features, args.features, 'Got expected feature bits'); } if (!!args.mtokens) { equal(parsed.mtokens, args.mtokens, 'Payment request mtokens expected'); } if (!!args.payment) { equal(parsed.payment, args.payment, 'Payment identifier expected'); } if (!!args.routes) { strictSame(parsed.routes, args.routes, 'Payment request as expected'); } if (!!args.tokens) { equal(parsed.tokens, args.tokens, 'Payment request tokens as expected'); } return end(); }); });