@t402/btc 2.7.0

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.
Files changed (62) hide show
  1. package/README.md +120 -0
  2. package/dist/cjs/exact/client/index.d.ts +89 -0
  3. package/dist/cjs/exact/client/index.js +145 -0
  4. package/dist/cjs/exact/client/index.js.map +1 -0
  5. package/dist/cjs/exact/facilitator/index.d.ts +114 -0
  6. package/dist/cjs/exact/facilitator/index.js +218 -0
  7. package/dist/cjs/exact/facilitator/index.js.map +1 -0
  8. package/dist/cjs/exact/server/index.d.ts +101 -0
  9. package/dist/cjs/exact/server/index.js +161 -0
  10. package/dist/cjs/exact/server/index.js.map +1 -0
  11. package/dist/cjs/index.d.ts +179 -0
  12. package/dist/cjs/index.js +849 -0
  13. package/dist/cjs/index.js.map +1 -0
  14. package/dist/cjs/lightning/client/index.d.ts +82 -0
  15. package/dist/cjs/lightning/client/index.js +114 -0
  16. package/dist/cjs/lightning/client/index.js.map +1 -0
  17. package/dist/cjs/lightning/facilitator/index.d.ts +93 -0
  18. package/dist/cjs/lightning/facilitator/index.js +211 -0
  19. package/dist/cjs/lightning/facilitator/index.js.map +1 -0
  20. package/dist/cjs/lightning/server/index.d.ts +96 -0
  21. package/dist/cjs/lightning/server/index.js +157 -0
  22. package/dist/cjs/lightning/server/index.js.map +1 -0
  23. package/dist/cjs/signer-B_Z4WGLa.d.ts +64 -0
  24. package/dist/esm/chunk-2DEKJ7ER.mjs +123 -0
  25. package/dist/esm/chunk-2DEKJ7ER.mjs.map +1 -0
  26. package/dist/esm/chunk-3IOPLDQH.mjs +74 -0
  27. package/dist/esm/chunk-3IOPLDQH.mjs.map +1 -0
  28. package/dist/esm/chunk-7IU3Z36R.mjs +103 -0
  29. package/dist/esm/chunk-7IU3Z36R.mjs.map +1 -0
  30. package/dist/esm/chunk-HNFWDITA.mjs +170 -0
  31. package/dist/esm/chunk-HNFWDITA.mjs.map +1 -0
  32. package/dist/esm/chunk-MX3PAUPJ.mjs +65 -0
  33. package/dist/esm/chunk-MX3PAUPJ.mjs.map +1 -0
  34. package/dist/esm/chunk-YJYTK2QQ.mjs +127 -0
  35. package/dist/esm/chunk-YJYTK2QQ.mjs.map +1 -0
  36. package/dist/esm/chunk-YWZC2RR7.mjs +38 -0
  37. package/dist/esm/chunk-YWZC2RR7.mjs.map +1 -0
  38. package/dist/esm/chunk-ZOL5R3HZ.mjs +177 -0
  39. package/dist/esm/chunk-ZOL5R3HZ.mjs.map +1 -0
  40. package/dist/esm/exact/client/index.d.mts +89 -0
  41. package/dist/esm/exact/client/index.mjs +11 -0
  42. package/dist/esm/exact/client/index.mjs.map +1 -0
  43. package/dist/esm/exact/facilitator/index.d.mts +114 -0
  44. package/dist/esm/exact/facilitator/index.mjs +11 -0
  45. package/dist/esm/exact/facilitator/index.mjs.map +1 -0
  46. package/dist/esm/exact/server/index.d.mts +101 -0
  47. package/dist/esm/exact/server/index.mjs +10 -0
  48. package/dist/esm/exact/server/index.mjs.map +1 -0
  49. package/dist/esm/index.d.mts +179 -0
  50. package/dist/esm/index.mjs +77 -0
  51. package/dist/esm/index.mjs.map +1 -0
  52. package/dist/esm/lightning/client/index.d.mts +82 -0
  53. package/dist/esm/lightning/client/index.mjs +11 -0
  54. package/dist/esm/lightning/client/index.mjs.map +1 -0
  55. package/dist/esm/lightning/facilitator/index.d.mts +93 -0
  56. package/dist/esm/lightning/facilitator/index.mjs +11 -0
  57. package/dist/esm/lightning/facilitator/index.mjs.map +1 -0
  58. package/dist/esm/lightning/server/index.d.mts +96 -0
  59. package/dist/esm/lightning/server/index.mjs +10 -0
  60. package/dist/esm/lightning/server/index.mjs.map +1 -0
  61. package/dist/esm/signer-B_Z4WGLa.d.mts +64 -0
  62. package/package.json +142 -0
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # @t402/btc
2
+
3
+ Bitcoin & Lightning Network payment mechanism for the t402 protocol.
4
+
5
+ Supports:
6
+
7
+ - **BTC On-chain**: PSBT-based payments using the `exact` scheme
8
+ - **Lightning Network**: BOLT11 invoice payments with preimage verification
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @t402/btc @t402/core
14
+ # or
15
+ pnpm add @t402/btc @t402/core
16
+ ```
17
+
18
+ For PSBT construction with bitcoinjs-lib (optional):
19
+
20
+ ```bash
21
+ npm install bitcoinjs-lib
22
+ ```
23
+
24
+ ## Networks
25
+
26
+ | Network | CAIP-2 ID |
27
+ | ----------------- | ----------------------------------------- |
28
+ | BTC Mainnet | `bip122:000000000019d6689c085ae165831e93` |
29
+ | BTC Testnet | `bip122:000000000933ea01ad0ee984209779ba` |
30
+ | Lightning Mainnet | `lightning:mainnet` |
31
+ | Lightning Testnet | `lightning:testnet` |
32
+
33
+ ## Usage
34
+
35
+ ### BTC On-chain Client
36
+
37
+ ```typescript
38
+ import { registerExactBtcScheme } from '@t402/btc/exact/client'
39
+ import { t402Client } from '@t402/core/client'
40
+
41
+ const client = new t402Client()
42
+ registerExactBtcScheme(client, {
43
+ signer: {
44
+ signPsbt: async (psbt) => {
45
+ /* sign PSBT */
46
+ },
47
+ getAddress: () => 'bc1q...',
48
+ getPublicKey: () => '02...',
49
+ },
50
+ })
51
+ ```
52
+
53
+ ### Lightning Client
54
+
55
+ ```typescript
56
+ import { registerLightningScheme } from '@t402/btc/lightning/client'
57
+ import { t402Client } from '@t402/core/client'
58
+
59
+ const client = new t402Client()
60
+ registerLightningScheme(client, {
61
+ signer: {
62
+ payInvoice: async (bolt11) => {
63
+ // Pay invoice via your Lightning node
64
+ return { preimage: '...', paymentHash: '...' }
65
+ },
66
+ getNodePubKey: () => '02...',
67
+ },
68
+ })
69
+ ```
70
+
71
+ ### Server (Resource Server)
72
+
73
+ ```typescript
74
+ import { registerExactBtcScheme } from '@t402/btc/exact/server'
75
+ import { registerLightningScheme } from '@t402/btc/lightning/server'
76
+ import { t402ResourceServer } from '@t402/core/server'
77
+
78
+ const server = new t402ResourceServer(facilitatorClient)
79
+
80
+ // BTC on-chain
81
+ registerExactBtcScheme(server, {
82
+ schemeConfig: { payTo: 'bc1q...' },
83
+ })
84
+
85
+ // Lightning
86
+ registerLightningScheme(server, {
87
+ schemeConfig: {
88
+ generateInvoice: async (amountSats, description, expiry) => {
89
+ // Generate BOLT11 invoice via your Lightning node
90
+ return { bolt11Invoice: 'lnbc...', paymentHash: '...' }
91
+ },
92
+ },
93
+ })
94
+ ```
95
+
96
+ ### Facilitator
97
+
98
+ ```typescript
99
+ import { registerExactBtcScheme } from '@t402/btc/exact/facilitator'
100
+ import { registerLightningScheme } from '@t402/btc/lightning/facilitator'
101
+ import { t402Facilitator } from '@t402/core/facilitator'
102
+
103
+ const facilitator = new t402Facilitator()
104
+
105
+ // BTC on-chain
106
+ registerExactBtcScheme(facilitator, {
107
+ signer: btcFacilitatorSigner,
108
+ networks: 'bip122:000000000019d6689c085ae165831e93',
109
+ })
110
+
111
+ // Lightning
112
+ registerLightningScheme(facilitator, {
113
+ signer: lnFacilitatorSigner,
114
+ networks: 'lightning:mainnet',
115
+ })
116
+ ```
117
+
118
+ ## License
119
+
120
+ Apache-2.0
@@ -0,0 +1,89 @@
1
+ import { SchemeNetworkClient, PaymentRequirements, PaymentPayload, Network } from '@t402/core/types';
2
+ import { C as ClientBtcSigner } from '../../signer-B_Z4WGLa.js';
3
+ import { PaymentPolicy, t402Client } from '@t402/core/client';
4
+
5
+ /**
6
+ * Bitcoin On-chain Client Scheme Implementation
7
+ *
8
+ * Creates payment payloads for Bitcoin on-chain transfers using the exact scheme.
9
+ * Builds PSBTs (Partially Signed Bitcoin Transactions) and signs them with the client's wallet.
10
+ */
11
+
12
+ /**
13
+ * Bitcoin client implementation for the Exact payment scheme.
14
+ *
15
+ * Creates signed PSBTs for on-chain Bitcoin payments that can be
16
+ * finalized and broadcast by a facilitator.
17
+ */
18
+ declare class ExactBtcScheme implements SchemeNetworkClient {
19
+ private readonly signer;
20
+ readonly scheme = "exact";
21
+ /**
22
+ * Creates a new ExactBtcScheme instance.
23
+ *
24
+ * @param signer - The Bitcoin signer for client operations
25
+ */
26
+ constructor(signer: ClientBtcSigner);
27
+ /**
28
+ * Creates a payment payload for the Exact scheme.
29
+ *
30
+ * The payload contains a signed PSBT with a single output
31
+ * paying the required amount to the payTo address.
32
+ *
33
+ * @param t402Version - The t402 protocol version
34
+ * @param paymentRequirements - The payment requirements
35
+ * @returns Promise resolving to a payment payload
36
+ */
37
+ createPaymentPayload(t402Version: number, paymentRequirements: PaymentRequirements): Promise<Pick<PaymentPayload, 't402Version' | 'payload'>>;
38
+ /**
39
+ * Build an unsigned PSBT for the payment.
40
+ *
41
+ * Creates a minimal PSBT representation with the required output.
42
+ * The actual UTXO selection and fee calculation should be handled
43
+ * by the signer implementation (which typically has wallet context).
44
+ *
45
+ * @param requirements - Payment requirements
46
+ * @returns Base64-encoded unsigned PSBT
47
+ */
48
+ private buildUnsignedPsbt;
49
+ }
50
+
51
+ /**
52
+ * Configuration options for registering BTC schemes to an t402Client
53
+ */
54
+ interface BtcClientConfig {
55
+ /**
56
+ * The Bitcoin signer to use for creating payment payloads
57
+ */
58
+ signer: ClientBtcSigner;
59
+ /**
60
+ * Optional policies to apply to the client
61
+ */
62
+ policies?: PaymentPolicy[];
63
+ /**
64
+ * Optional specific networks to register
65
+ * If not provided, registers wildcard support (bip122:*)
66
+ */
67
+ networks?: Network[];
68
+ }
69
+ /**
70
+ * Registers Bitcoin exact payment schemes to an t402Client instance.
71
+ *
72
+ * @param client - The t402Client instance to register schemes to
73
+ * @param config - Configuration for BTC client registration
74
+ * @returns The client instance for chaining
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * import { registerExactBtcScheme } from "@t402/btc/exact/client";
79
+ * import { t402Client } from "@t402/core/client";
80
+ *
81
+ * const client = new t402Client();
82
+ * registerExactBtcScheme(client, {
83
+ * signer: myBtcSigner,
84
+ * });
85
+ * ```
86
+ */
87
+ declare function registerExactBtcScheme(client: t402Client, config: BtcClientConfig): t402Client;
88
+
89
+ export { type BtcClientConfig, ExactBtcScheme, registerExactBtcScheme };
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+
22
+ // src/exact/client/index.ts
23
+ var client_exports = {};
24
+ __export(client_exports, {
25
+ ExactBtcScheme: () => ExactBtcScheme,
26
+ registerExactBtcScheme: () => registerExactBtcScheme
27
+ });
28
+ module.exports = __toCommonJS(client_exports);
29
+
30
+ // src/constants.ts
31
+ var BTC_MAINNET = "bip122:000000000019d6689c085ae165831e93";
32
+ var BTC_TESTNET = "bip122:000000000933ea01ad0ee984209779ba";
33
+ var LIGHTNING_MAINNET = "lightning:mainnet";
34
+ var LIGHTNING_TESTNET = "lightning:testnet";
35
+ var BTC_NETWORKS = [BTC_MAINNET, BTC_TESTNET];
36
+ var LIGHTNING_NETWORKS = [LIGHTNING_MAINNET, LIGHTNING_TESTNET];
37
+ var ALL_NETWORKS = [...BTC_NETWORKS, ...LIGHTNING_NETWORKS];
38
+ var DUST_LIMIT = 546;
39
+ var SCHEME_EXACT = "exact";
40
+ var MAINNET_ADDRESS_PREFIXES = ["bc1", "1", "3"];
41
+ var TESTNET_ADDRESS_PREFIXES = ["tb1", "m", "n", "2"];
42
+
43
+ // src/utils.ts
44
+ function validateBitcoinAddress(address) {
45
+ if (!address || address.length < 14 || address.length > 90) {
46
+ return false;
47
+ }
48
+ const allPrefixes = [...MAINNET_ADDRESS_PREFIXES, ...TESTNET_ADDRESS_PREFIXES];
49
+ return allPrefixes.some((prefix) => address.startsWith(prefix));
50
+ }
51
+
52
+ // src/exact/client/scheme.ts
53
+ var ExactBtcScheme = class {
54
+ /**
55
+ * Creates a new ExactBtcScheme instance.
56
+ *
57
+ * @param signer - The Bitcoin signer for client operations
58
+ */
59
+ constructor(signer) {
60
+ this.signer = signer;
61
+ __publicField(this, "scheme", SCHEME_EXACT);
62
+ }
63
+ /**
64
+ * Creates a payment payload for the Exact scheme.
65
+ *
66
+ * The payload contains a signed PSBT with a single output
67
+ * paying the required amount to the payTo address.
68
+ *
69
+ * @param t402Version - The t402 protocol version
70
+ * @param paymentRequirements - The payment requirements
71
+ * @returns Promise resolving to a payment payload
72
+ */
73
+ async createPaymentPayload(t402Version, paymentRequirements) {
74
+ if (!paymentRequirements.payTo) {
75
+ throw new Error("PayTo address is required");
76
+ }
77
+ if (!paymentRequirements.amount) {
78
+ throw new Error("Amount is required");
79
+ }
80
+ if (!validateBitcoinAddress(paymentRequirements.payTo)) {
81
+ throw new Error(`Invalid Bitcoin address: ${paymentRequirements.payTo}`);
82
+ }
83
+ const amountSats = BigInt(paymentRequirements.amount);
84
+ if (amountSats < BigInt(DUST_LIMIT)) {
85
+ throw new Error(`Amount ${amountSats} satoshis is below dust limit (${DUST_LIMIT})`);
86
+ }
87
+ const unsignedPsbt = this.buildUnsignedPsbt(paymentRequirements);
88
+ const signedPsbt = await this.signer.signPsbt(unsignedPsbt);
89
+ const payload = {
90
+ signedPsbt
91
+ };
92
+ return {
93
+ t402Version,
94
+ payload
95
+ };
96
+ }
97
+ /**
98
+ * Build an unsigned PSBT for the payment.
99
+ *
100
+ * Creates a minimal PSBT representation with the required output.
101
+ * The actual UTXO selection and fee calculation should be handled
102
+ * by the signer implementation (which typically has wallet context).
103
+ *
104
+ * @param requirements - Payment requirements
105
+ * @returns Base64-encoded unsigned PSBT
106
+ */
107
+ buildUnsignedPsbt(requirements) {
108
+ const psbtData = {
109
+ outputs: [
110
+ {
111
+ address: requirements.payTo,
112
+ value: requirements.amount
113
+ }
114
+ ],
115
+ network: requirements.network,
116
+ fromAddress: this.signer.getAddress(),
117
+ fromPubKey: this.signer.getPublicKey()
118
+ };
119
+ return Buffer.from(JSON.stringify(psbtData)).toString("base64");
120
+ }
121
+ };
122
+
123
+ // src/exact/client/register.ts
124
+ function registerExactBtcScheme(client, config) {
125
+ const scheme = new ExactBtcScheme(config.signer);
126
+ if (config.networks && config.networks.length > 0) {
127
+ config.networks.forEach((network) => {
128
+ client.register(network, scheme);
129
+ });
130
+ } else {
131
+ client.register("bip122:*", scheme);
132
+ }
133
+ if (config.policies) {
134
+ config.policies.forEach((policy) => {
135
+ client.registerPolicy(policy);
136
+ });
137
+ }
138
+ return client;
139
+ }
140
+ // Annotate the CommonJS export names for ESM import in node:
141
+ 0 && (module.exports = {
142
+ ExactBtcScheme,
143
+ registerExactBtcScheme
144
+ });
145
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/exact/client/index.ts","../../../../src/constants.ts","../../../../src/utils.ts","../../../../src/exact/client/scheme.ts","../../../../src/exact/client/register.ts"],"sourcesContent":["export { ExactBtcScheme } from './scheme.js'\nexport { registerExactBtcScheme } from './register.js'\nexport type { BtcClientConfig } from './register.js'\n","/**\n * Bitcoin & Lightning Network Constants\n *\n * CAIP-2 network identifiers, dust limits, and fee constants.\n */\n\n/**\n * CAIP-2 Network Identifiers for Bitcoin\n * Uses BIP-122 chain genesis block hashes\n */\nexport const BTC_MAINNET = 'bip122:000000000019d6689c085ae165831e93'\nexport const BTC_TESTNET = 'bip122:000000000933ea01ad0ee984209779ba'\n\n/**\n * CAIP-2 Network Identifiers for Lightning Network\n */\nexport const LIGHTNING_MAINNET = 'lightning:mainnet'\nexport const LIGHTNING_TESTNET = 'lightning:testnet'\n\n/**\n * All supported BTC on-chain networks\n */\nexport const BTC_NETWORKS = [BTC_MAINNET, BTC_TESTNET] as const\n\n/**\n * All supported Lightning networks\n */\nexport const LIGHTNING_NETWORKS = [LIGHTNING_MAINNET, LIGHTNING_TESTNET] as const\n\n/**\n * All supported networks (on-chain + Lightning)\n */\nexport const ALL_NETWORKS = [...BTC_NETWORKS, ...LIGHTNING_NETWORKS] as const\n\nexport type BtcNetwork = (typeof BTC_NETWORKS)[number]\nexport type LightningNetwork = (typeof LIGHTNING_NETWORKS)[number]\n\n/**\n * Dust limit in satoshis - minimum viable output value\n * Outputs below this threshold are rejected by Bitcoin nodes\n */\nexport const DUST_LIMIT = 546\n\n/**\n * Minimum relay fee in satoshis\n * Transactions with fees below this are not relayed by default\n */\nexport const MIN_RELAY_FEE = 1000\n\n/**\n * Satoshis per BTC\n */\nexport const SATS_PER_BTC = 100_000_000\n\n/**\n * Scheme identifiers\n */\nexport const SCHEME_EXACT = 'exact'\n\n/**\n * Default timeout for payment validity (in seconds)\n */\nexport const DEFAULT_VALIDITY_DURATION = 3600 // 1 hour\n\n/**\n * Bitcoin address prefixes for basic validation\n */\nexport const MAINNET_ADDRESS_PREFIXES = ['bc1', '1', '3']\nexport const TESTNET_ADDRESS_PREFIXES = ['tb1', 'm', 'n', '2']\n","/**\n * Bitcoin & Lightning Utility Functions\n *\n * Helper functions for address validation, unit conversion,\n * and invoice validation.\n */\n\nimport { SATS_PER_BTC, MAINNET_ADDRESS_PREFIXES, TESTNET_ADDRESS_PREFIXES } from './constants.js'\n\n/**\n * Convert satoshis to BTC\n *\n * @param sats - Amount in satoshis\n * @returns Amount in BTC as string (to avoid floating point issues)\n */\nexport function satoshisToBtc(sats: bigint | number | string): string {\n const satsBigInt = BigInt(sats)\n const whole = satsBigInt / BigInt(SATS_PER_BTC)\n const frac = satsBigInt % BigInt(SATS_PER_BTC)\n\n if (frac === 0n) {\n return whole.toString()\n }\n\n const fracStr = frac.toString().padStart(8, '0')\n return `${whole}.${fracStr}`.replace(/\\.?0+$/, '')\n}\n\n/**\n * Convert BTC to satoshis\n *\n * @param btc - Amount in BTC (string or number)\n * @returns Amount in satoshis as bigint\n */\nexport function btcToSatoshis(btc: string | number): bigint {\n const btcStr = typeof btc === 'number' ? btc.toString() : btc\n const [wholePart, fracPart = ''] = btcStr.split('.')\n const paddedFrac = fracPart.padEnd(8, '0').slice(0, 8)\n const combined = wholePart + paddedFrac\n const result = BigInt(combined.replace(/^0+/, '') || '0')\n return result\n}\n\n/**\n * Validate a Bitcoin address (basic format validation)\n *\n * Checks address prefix against known formats:\n * - Mainnet: bc1 (bech32), 1 (P2PKH), 3 (P2SH)\n * - Testnet: tb1 (bech32), m/n (P2PKH), 2 (P2SH)\n *\n * @param address - Bitcoin address to validate\n * @returns true if the address has a valid format\n */\nexport function validateBitcoinAddress(address: string): boolean {\n if (!address || address.length < 14 || address.length > 90) {\n return false\n }\n\n const allPrefixes = [...MAINNET_ADDRESS_PREFIXES, ...TESTNET_ADDRESS_PREFIXES]\n return allPrefixes.some((prefix) => address.startsWith(prefix))\n}\n\n/**\n * Check if a Bitcoin address is for mainnet\n *\n * @param address - Bitcoin address\n * @returns true if mainnet address\n */\nexport function isMainnetAddress(address: string): boolean {\n return MAINNET_ADDRESS_PREFIXES.some((prefix) => address.startsWith(prefix))\n}\n\n/**\n * Check if a Bitcoin address is for testnet\n *\n * @param address - Bitcoin address\n * @returns true if testnet address\n */\nexport function isTestnetAddress(address: string): boolean {\n return TESTNET_ADDRESS_PREFIXES.some((prefix) => address.startsWith(prefix))\n}\n\n/**\n * Validate a BOLT11 Lightning invoice (basic format validation)\n *\n * BOLT11 invoices follow the format:\n * - lnbc... for mainnet\n * - lntb... for testnet\n * - lnbcrt... for regtest\n *\n * @param invoice - BOLT11 invoice string\n * @returns true if the invoice has a valid format\n */\nexport function validateBolt11Invoice(invoice: string): boolean {\n if (!invoice || invoice.length < 20) {\n return false\n }\n\n const lower = invoice.toLowerCase()\n return lower.startsWith('lnbc') || lower.startsWith('lntb') || lower.startsWith('lnbcrt')\n}\n\n/**\n * Validate a hex-encoded string\n *\n * @param hex - String to validate\n * @param expectedLength - Expected byte length (hex length / 2)\n * @returns true if valid hex of expected length\n */\nexport function isValidHex(hex: string, expectedLength?: number): boolean {\n if (!/^[0-9a-fA-F]+$/.test(hex)) {\n return false\n }\n if (expectedLength !== undefined && hex.length !== expectedLength * 2) {\n return false\n }\n return true\n}\n","/**\n * Bitcoin On-chain Client Scheme Implementation\n *\n * Creates payment payloads for Bitcoin on-chain transfers using the exact scheme.\n * Builds PSBTs (Partially Signed Bitcoin Transactions) and signs them with the client's wallet.\n */\n\nimport type { PaymentPayload, PaymentRequirements, SchemeNetworkClient } from '@t402/core/types'\nimport type { ClientBtcSigner } from '../../signer.js'\nimport type { BtcOnchainPayload } from '../../types.js'\nimport { SCHEME_EXACT, DUST_LIMIT } from '../../constants.js'\nimport { validateBitcoinAddress } from '../../utils.js'\n\n/**\n * Bitcoin client implementation for the Exact payment scheme.\n *\n * Creates signed PSBTs for on-chain Bitcoin payments that can be\n * finalized and broadcast by a facilitator.\n */\nexport class ExactBtcScheme implements SchemeNetworkClient {\n readonly scheme = SCHEME_EXACT\n\n /**\n * Creates a new ExactBtcScheme instance.\n *\n * @param signer - The Bitcoin signer for client operations\n */\n constructor(private readonly signer: ClientBtcSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme.\n *\n * The payload contains a signed PSBT with a single output\n * paying the required amount to the payTo address.\n *\n * @param t402Version - The t402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n t402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<Pick<PaymentPayload, 't402Version' | 'payload'>> {\n // Validate required fields\n if (!paymentRequirements.payTo) {\n throw new Error('PayTo address is required')\n }\n if (!paymentRequirements.amount) {\n throw new Error('Amount is required')\n }\n\n // Validate address format\n if (!validateBitcoinAddress(paymentRequirements.payTo)) {\n throw new Error(`Invalid Bitcoin address: ${paymentRequirements.payTo}`)\n }\n\n // Validate amount is above dust limit\n const amountSats = BigInt(paymentRequirements.amount)\n if (amountSats < BigInt(DUST_LIMIT)) {\n throw new Error(`Amount ${amountSats} satoshis is below dust limit (${DUST_LIMIT})`)\n }\n\n // Build an unsigned PSBT\n // The PSBT contains: output to payTo address for the required amount\n // Input selection and fee calculation are handled by the signer\n const unsignedPsbt = this.buildUnsignedPsbt(paymentRequirements)\n\n // Sign the PSBT\n const signedPsbt = await this.signer.signPsbt(unsignedPsbt)\n\n // Create payload\n const payload: BtcOnchainPayload = {\n signedPsbt,\n }\n\n return {\n t402Version,\n payload,\n }\n }\n\n /**\n * Build an unsigned PSBT for the payment.\n *\n * Creates a minimal PSBT representation with the required output.\n * The actual UTXO selection and fee calculation should be handled\n * by the signer implementation (which typically has wallet context).\n *\n * @param requirements - Payment requirements\n * @returns Base64-encoded unsigned PSBT\n */\n private buildUnsignedPsbt(requirements: PaymentRequirements): string {\n // Encode payment details as a JSON payload in the PSBT\n // The signer is responsible for building the full PSBT\n // with proper UTXO selection and fee estimation\n const psbtData = {\n outputs: [\n {\n address: requirements.payTo,\n value: requirements.amount,\n },\n ],\n network: requirements.network,\n fromAddress: this.signer.getAddress(),\n fromPubKey: this.signer.getPublicKey(),\n }\n\n // Encode as base64 for transport\n return Buffer.from(JSON.stringify(psbtData)).toString('base64')\n }\n}\n","import { t402Client, PaymentPolicy } from '@t402/core/client'\nimport { Network } from '@t402/core/types'\nimport { ClientBtcSigner } from '../../signer.js'\nimport { ExactBtcScheme } from './scheme.js'\n\n/**\n * Configuration options for registering BTC schemes to an t402Client\n */\nexport interface BtcClientConfig {\n /**\n * The Bitcoin signer to use for creating payment payloads\n */\n signer: ClientBtcSigner\n\n /**\n * Optional policies to apply to the client\n */\n policies?: PaymentPolicy[]\n\n /**\n * Optional specific networks to register\n * If not provided, registers wildcard support (bip122:*)\n */\n networks?: Network[]\n}\n\n/**\n * Registers Bitcoin exact payment schemes to an t402Client instance.\n *\n * @param client - The t402Client instance to register schemes to\n * @param config - Configuration for BTC client registration\n * @returns The client instance for chaining\n *\n * @example\n * ```typescript\n * import { registerExactBtcScheme } from \"@t402/btc/exact/client\";\n * import { t402Client } from \"@t402/core/client\";\n *\n * const client = new t402Client();\n * registerExactBtcScheme(client, {\n * signer: myBtcSigner,\n * });\n * ```\n */\nexport function registerExactBtcScheme(client: t402Client, config: BtcClientConfig): t402Client {\n const scheme = new ExactBtcScheme(config.signer)\n\n if (config.networks && config.networks.length > 0) {\n config.networks.forEach((network) => {\n client.register(network, scheme)\n })\n } else {\n client.register('bip122:*', scheme)\n }\n\n if (config.policies) {\n config.policies.forEach((policy) => {\n client.registerPolicy(policy)\n })\n }\n\n return client\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUO,IAAM,cAAc;AACpB,IAAM,cAAc;AAKpB,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAK1B,IAAM,eAAe,CAAC,aAAa,WAAW;AAK9C,IAAM,qBAAqB,CAAC,mBAAmB,iBAAiB;AAKhE,IAAM,eAAe,CAAC,GAAG,cAAc,GAAG,kBAAkB;AAS5D,IAAM,aAAa;AAgBnB,IAAM,eAAe;AAUrB,IAAM,2BAA2B,CAAC,OAAO,KAAK,GAAG;AACjD,IAAM,2BAA2B,CAAC,OAAO,KAAK,KAAK,GAAG;;;ACftD,SAAS,uBAAuB,SAA0B;AAC/D,MAAI,CAAC,WAAW,QAAQ,SAAS,MAAM,QAAQ,SAAS,IAAI;AAC1D,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,CAAC,GAAG,0BAA0B,GAAG,wBAAwB;AAC7E,SAAO,YAAY,KAAK,CAAC,WAAW,QAAQ,WAAW,MAAM,CAAC;AAChE;;;ACzCO,IAAM,iBAAN,MAAoD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzD,YAA6B,QAAyB;AAAzB;AAP7B,wBAAS,UAAS;AAAA,EAOqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYvD,MAAM,qBACJ,aACA,qBAC0D;AAE1D,QAAI,CAAC,oBAAoB,OAAO;AAC9B,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AACA,QAAI,CAAC,oBAAoB,QAAQ;AAC/B,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AAGA,QAAI,CAAC,uBAAuB,oBAAoB,KAAK,GAAG;AACtD,YAAM,IAAI,MAAM,4BAA4B,oBAAoB,KAAK,EAAE;AAAA,IACzE;AAGA,UAAM,aAAa,OAAO,oBAAoB,MAAM;AACpD,QAAI,aAAa,OAAO,UAAU,GAAG;AACnC,YAAM,IAAI,MAAM,UAAU,UAAU,kCAAkC,UAAU,GAAG;AAAA,IACrF;AAKA,UAAM,eAAe,KAAK,kBAAkB,mBAAmB;AAG/D,UAAM,aAAa,MAAM,KAAK,OAAO,SAAS,YAAY;AAG1D,UAAM,UAA6B;AAAA,MACjC;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,kBAAkB,cAA2C;AAInE,UAAM,WAAW;AAAA,MACf,SAAS;AAAA,QACP;AAAA,UACE,SAAS,aAAa;AAAA,UACtB,OAAO,aAAa;AAAA,QACtB;AAAA,MACF;AAAA,MACA,SAAS,aAAa;AAAA,MACtB,aAAa,KAAK,OAAO,WAAW;AAAA,MACpC,YAAY,KAAK,OAAO,aAAa;AAAA,IACvC;AAGA,WAAO,OAAO,KAAK,KAAK,UAAU,QAAQ,CAAC,EAAE,SAAS,QAAQ;AAAA,EAChE;AACF;;;AClEO,SAAS,uBAAuB,QAAoB,QAAqC;AAC9F,QAAM,SAAS,IAAI,eAAe,OAAO,MAAM;AAE/C,MAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAAG;AACjD,WAAO,SAAS,QAAQ,CAAC,YAAY;AACnC,aAAO,SAAS,SAAS,MAAM;AAAA,IACjC,CAAC;AAAA,EACH,OAAO;AACL,WAAO,SAAS,YAAY,MAAM;AAAA,EACpC;AAEA,MAAI,OAAO,UAAU;AACnB,WAAO,SAAS,QAAQ,CAAC,WAAW;AAClC,aAAO,eAAe,MAAM;AAAA,IAC9B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":[]}
@@ -0,0 +1,114 @@
1
+ import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, VerifyResponse, SettleResponse, Network } from '@t402/core/types';
2
+ import { t402Facilitator } from '@t402/core/facilitator';
3
+
4
+ /**
5
+ * Bitcoin On-chain Facilitator Scheme Implementation
6
+ *
7
+ * Verifies and settles Bitcoin on-chain payments using the exact scheme.
8
+ * Validates signed PSBTs and broadcasts transactions to the Bitcoin network.
9
+ */
10
+
11
+ /**
12
+ * Facilitator BTC signer interface for verify and settle operations
13
+ */
14
+ interface FacilitatorBtcSigner {
15
+ /**
16
+ * Get all addresses this facilitator can use
17
+ */
18
+ getAddresses(): readonly string[];
19
+ /**
20
+ * Verify a signed PSBT
21
+ * Checks that outputs match expected values and signatures are valid
22
+ *
23
+ * @param params - Verification parameters
24
+ * @returns Verification result
25
+ */
26
+ verifyPsbt(params: {
27
+ signedPsbt: string;
28
+ expectedPayTo: string;
29
+ expectedAmount: string;
30
+ }): Promise<{
31
+ valid: boolean;
32
+ reason?: string;
33
+ payer?: string;
34
+ }>;
35
+ /**
36
+ * Finalize and broadcast a signed PSBT
37
+ *
38
+ * @param signedPsbt - Base64-encoded signed PSBT
39
+ * @returns Transaction ID
40
+ */
41
+ broadcastPsbt(signedPsbt: string): Promise<string>;
42
+ /**
43
+ * Wait for a transaction to be confirmed
44
+ *
45
+ * @param txId - Transaction ID
46
+ * @param confirmations - Number of confirmations to wait for
47
+ * @returns Confirmation result
48
+ */
49
+ waitForConfirmation(txId: string, confirmations?: number): Promise<{
50
+ confirmed: boolean;
51
+ txId: string;
52
+ blockHash?: string;
53
+ confirmations: number;
54
+ }>;
55
+ }
56
+ /**
57
+ * Bitcoin facilitator implementation for the Exact payment scheme.
58
+ *
59
+ * Verifies signed PSBTs and broadcasts transactions to settle payments.
60
+ */
61
+ declare class ExactBtcScheme implements SchemeNetworkFacilitator {
62
+ private readonly signer;
63
+ readonly scheme = "exact";
64
+ readonly caipFamily = "bip122:*";
65
+ constructor(signer: FacilitatorBtcSigner);
66
+ /**
67
+ * Get mechanism-specific extra data for the supported kinds endpoint.
68
+ * Bitcoin on-chain has no extra data.
69
+ */
70
+ getExtra(_network: string): Record<string, unknown> | undefined;
71
+ /**
72
+ * Get signer addresses used by this facilitator.
73
+ */
74
+ getSigners(_network: string): string[];
75
+ /**
76
+ * Verifies a payment payload.
77
+ *
78
+ * Validates:
79
+ * 1. Scheme and network matching
80
+ * 2. PSBT structure and signatures
81
+ * 3. Output matches (payTo, amount)
82
+ * 4. Amount above dust limit
83
+ */
84
+ verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
85
+ /**
86
+ * Settles a payment by finalizing and broadcasting the PSBT.
87
+ */
88
+ settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
89
+ }
90
+
91
+ /**
92
+ * Configuration options for registering BTC schemes to an t402Facilitator
93
+ */
94
+ interface BtcFacilitatorConfig {
95
+ /**
96
+ * The Bitcoin signer for facilitator operations (verify and settle)
97
+ */
98
+ signer: FacilitatorBtcSigner;
99
+ /**
100
+ * Networks to register (single network or array of networks)
101
+ * Examples: "bip122:000000000019d6689c085ae165831e93"
102
+ */
103
+ networks: Network | Network[];
104
+ }
105
+ /**
106
+ * Registers Bitcoin exact payment schemes to an t402Facilitator instance.
107
+ *
108
+ * @param facilitator - The t402Facilitator instance to register schemes to
109
+ * @param config - Configuration for BTC facilitator registration
110
+ * @returns The facilitator instance for chaining
111
+ */
112
+ declare function registerExactBtcScheme(facilitator: t402Facilitator, config: BtcFacilitatorConfig): t402Facilitator;
113
+
114
+ export { type BtcFacilitatorConfig, ExactBtcScheme, type FacilitatorBtcSigner, registerExactBtcScheme };