clawdentials-mcp 0.1.0 → 0.7.2
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/README.md +310 -58
- package/dist/index.d.ts +1 -1
- package/dist/index.js +225 -18
- package/dist/schemas/index.d.ts +141 -0
- package/dist/schemas/index.js +54 -0
- package/dist/services/firestore.d.ts +45 -2
- package/dist/services/firestore.js +410 -6
- package/dist/services/payments/alby.d.ts +104 -0
- package/dist/services/payments/alby.js +239 -0
- package/dist/services/payments/breez.d.ts +91 -0
- package/dist/services/payments/breez.js +267 -0
- package/dist/services/payments/cashu.d.ts +127 -0
- package/dist/services/payments/cashu.js +248 -0
- package/dist/services/payments/coinremitter.d.ts +84 -0
- package/dist/services/payments/coinremitter.js +176 -0
- package/dist/services/payments/index.d.ts +132 -0
- package/dist/services/payments/index.js +180 -0
- package/dist/services/payments/oxapay.d.ts +89 -0
- package/dist/services/payments/oxapay.js +221 -0
- package/dist/services/payments/x402.d.ts +61 -0
- package/dist/services/payments/x402.js +94 -0
- package/dist/services/payments/zbd.d.ts +88 -0
- package/dist/services/payments/zbd.js +221 -0
- package/dist/tools/admin.d.ts +195 -0
- package/dist/tools/admin.js +210 -0
- package/dist/tools/agent.d.ts +197 -0
- package/dist/tools/agent.js +200 -0
- package/dist/tools/escrow.d.ts +74 -16
- package/dist/tools/escrow.js +139 -28
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/payment.d.ts +144 -0
- package/dist/tools/payment.js +376 -0
- package/dist/types/index.d.ts +44 -1
- package/package.json +18 -2
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alby Payment Service - Bitcoin on Lightning
|
|
3
|
+
*
|
|
4
|
+
* Uses Alby API with Nostr Wallet Connect (NWC) for self-custodial Lightning payments.
|
|
5
|
+
* Docs: https://guides.getalby.com/developer-guide
|
|
6
|
+
* Fee: ~0% (just Lightning network fees)
|
|
7
|
+
*/
|
|
8
|
+
// Configuration
|
|
9
|
+
// NWC connection string format: nostr+walletconnect://pubkey?relay=wss://...&secret=...
|
|
10
|
+
const ALBY_NWC_URL = process.env.ALBY_NWC_URL || '';
|
|
11
|
+
const ALBY_WEBHOOK_URL = process.env.ALBY_WEBHOOK_URL || '';
|
|
12
|
+
// Alby API (for account-based operations)
|
|
13
|
+
const ALBY_API_KEY = process.env.ALBY_API_KEY || '';
|
|
14
|
+
const API_BASE = 'https://api.getalby.com';
|
|
15
|
+
// Exchange rate (sats per USD) - in production, fetch from API
|
|
16
|
+
const SATS_PER_USD = parseInt(process.env.ALBY_SATS_PER_USD || '1000', 10);
|
|
17
|
+
/**
|
|
18
|
+
* Convert USD to sats
|
|
19
|
+
*/
|
|
20
|
+
function usdToSats(usd) {
|
|
21
|
+
return Math.floor(usd * SATS_PER_USD);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert sats to USD
|
|
25
|
+
*/
|
|
26
|
+
function satsToUsd(sats) {
|
|
27
|
+
return sats / SATS_PER_USD;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Make API request to Alby
|
|
31
|
+
*/
|
|
32
|
+
async function apiRequest(endpoint, method = 'POST', data) {
|
|
33
|
+
if (!ALBY_API_KEY) {
|
|
34
|
+
throw new Error('ALBY_API_KEY not configured');
|
|
35
|
+
}
|
|
36
|
+
const response = await fetch(`${API_BASE}${endpoint}`, {
|
|
37
|
+
method,
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
Authorization: `Bearer ${ALBY_API_KEY}`,
|
|
41
|
+
},
|
|
42
|
+
body: data ? JSON.stringify(data) : undefined,
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const error = await response.text();
|
|
46
|
+
throw new Error(`Alby API error: ${error}`);
|
|
47
|
+
}
|
|
48
|
+
return response.json();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create a Lightning invoice for BTC deposit
|
|
52
|
+
*/
|
|
53
|
+
export async function createAlbyDeposit(request) {
|
|
54
|
+
if (!ALBY_API_KEY) {
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
error: 'ALBY_API_KEY not configured. Get one at https://getalby.com',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const amountSats = usdToSats(request.amount);
|
|
62
|
+
const result = await apiRequest('/invoices', 'POST', {
|
|
63
|
+
amount: amountSats,
|
|
64
|
+
description: request.description || `Clawdentials deposit for ${request.agentId}`,
|
|
65
|
+
memo: request.agentId, // Store agentId in memo for webhook processing
|
|
66
|
+
});
|
|
67
|
+
// Alby invoices expire in 1 hour by default
|
|
68
|
+
const expiresAt = new Date(Date.now() + 60 * 60 * 1000);
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
deposit: {
|
|
72
|
+
id: `alby_${result.payment_hash}`,
|
|
73
|
+
agentId: request.agentId,
|
|
74
|
+
amount: request.amount,
|
|
75
|
+
currency: 'BTC',
|
|
76
|
+
network: 'lightning',
|
|
77
|
+
status: 'pending',
|
|
78
|
+
provider: 'alby',
|
|
79
|
+
externalId: result.payment_hash,
|
|
80
|
+
paymentAddress: result.payment_request, // bolt11 invoice
|
|
81
|
+
paymentUrl: null,
|
|
82
|
+
createdAt: new Date(),
|
|
83
|
+
expiresAt,
|
|
84
|
+
completedAt: null,
|
|
85
|
+
txHash: null,
|
|
86
|
+
},
|
|
87
|
+
invoice: {
|
|
88
|
+
paymentHash: result.payment_hash,
|
|
89
|
+
paymentRequest: result.payment_request,
|
|
90
|
+
amountSats,
|
|
91
|
+
expiresAt,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
error: error instanceof Error ? error.message : 'Failed to create Lightning invoice',
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Check invoice status
|
|
104
|
+
*/
|
|
105
|
+
export async function getInvoiceStatus(paymentHash) {
|
|
106
|
+
if (!ALBY_API_KEY) {
|
|
107
|
+
return { success: false, error: 'ALBY_API_KEY not configured' };
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const result = await apiRequest(`/invoices/${paymentHash}`, 'GET');
|
|
111
|
+
return {
|
|
112
|
+
success: true,
|
|
113
|
+
status: result.state, // CREATED, SETTLED, CANCELED
|
|
114
|
+
paid: result.state === 'SETTLED',
|
|
115
|
+
amountSats: result.amount,
|
|
116
|
+
amountUsd: satsToUsd(result.amount),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
return {
|
|
121
|
+
success: false,
|
|
122
|
+
error: error instanceof Error ? error.message : 'Failed to get invoice status',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Process webhook callback from Alby
|
|
128
|
+
*/
|
|
129
|
+
export function parseWebhookPayload(body) {
|
|
130
|
+
return {
|
|
131
|
+
paymentHash: body.payment_hash,
|
|
132
|
+
status: body.state,
|
|
133
|
+
amountSats: body.amount,
|
|
134
|
+
amountUsd: satsToUsd(body.amount),
|
|
135
|
+
memo: body.memo || body.description || '',
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Send Lightning payment (for withdrawals)
|
|
140
|
+
*/
|
|
141
|
+
export async function sendAlbyPayment(destination, // Lightning invoice or Lightning Address
|
|
142
|
+
amountUsd) {
|
|
143
|
+
if (!ALBY_API_KEY) {
|
|
144
|
+
return { success: false, error: 'ALBY_API_KEY not configured' };
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
// Check if it's a Lightning Address (contains @)
|
|
148
|
+
if (destination.includes('@')) {
|
|
149
|
+
// Pay to Lightning Address
|
|
150
|
+
const amountSats = usdToSats(amountUsd);
|
|
151
|
+
const result = await apiRequest('/payments/lnaddress', 'POST', {
|
|
152
|
+
lnaddress: destination,
|
|
153
|
+
amount: amountSats,
|
|
154
|
+
comment: 'Clawdentials withdrawal',
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
success: true,
|
|
158
|
+
paymentHash: result.payment_hash,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
// Pay bolt11 invoice directly
|
|
163
|
+
const result = await apiRequest('/payments/bolt11', 'POST', {
|
|
164
|
+
invoice: destination,
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
success: true,
|
|
168
|
+
paymentHash: result.payment_hash,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
error: error instanceof Error ? error.message : 'Failed to send payment',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get wallet balance
|
|
181
|
+
*/
|
|
182
|
+
export async function getWalletBalance() {
|
|
183
|
+
if (!ALBY_API_KEY) {
|
|
184
|
+
return { success: false, error: 'ALBY_API_KEY not configured' };
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
const result = await apiRequest('/balance', 'GET');
|
|
188
|
+
return {
|
|
189
|
+
success: true,
|
|
190
|
+
balanceSats: result.balance,
|
|
191
|
+
balanceUsd: satsToUsd(result.balance),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
return {
|
|
196
|
+
success: false,
|
|
197
|
+
error: error instanceof Error ? error.message : 'Failed to get balance',
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Decode a Lightning invoice to get amount and details
|
|
203
|
+
*/
|
|
204
|
+
export async function decodeInvoice(invoice) {
|
|
205
|
+
try {
|
|
206
|
+
// Use Alby's decode endpoint or a local decoder
|
|
207
|
+
const result = await apiRequest('/decode/bolt11', 'POST', { invoice });
|
|
208
|
+
return {
|
|
209
|
+
success: true,
|
|
210
|
+
amountSats: result.amount,
|
|
211
|
+
amountUsd: satsToUsd(result.amount),
|
|
212
|
+
description: result.description,
|
|
213
|
+
paymentHash: result.payment_hash,
|
|
214
|
+
expiresAt: result.expires_at ? new Date(result.expires_at * 1000) : undefined,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
return {
|
|
219
|
+
success: false,
|
|
220
|
+
error: error instanceof Error ? error.message : 'Failed to decode invoice',
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
export const albyService = {
|
|
225
|
+
createDeposit: createAlbyDeposit,
|
|
226
|
+
getInvoiceStatus,
|
|
227
|
+
parseWebhookPayload,
|
|
228
|
+
sendPayment: sendAlbyPayment,
|
|
229
|
+
getWalletBalance,
|
|
230
|
+
decodeInvoice,
|
|
231
|
+
usdToSats,
|
|
232
|
+
satsToUsd,
|
|
233
|
+
config: {
|
|
234
|
+
configured: !!ALBY_API_KEY,
|
|
235
|
+
nwcConfigured: !!ALBY_NWC_URL,
|
|
236
|
+
webhookUrl: ALBY_WEBHOOK_URL,
|
|
237
|
+
satsPerUsd: SATS_PER_USD,
|
|
238
|
+
},
|
|
239
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Breez SDK Payment Service - Bitcoin on Lightning (Nodeless/Liquid)
|
|
3
|
+
*
|
|
4
|
+
* Uses Breez SDK Liquid for self-custodial Lightning payments.
|
|
5
|
+
* Docs: https://sdk-doc-liquid.breez.technology/
|
|
6
|
+
* Fee: Network fees only (no platform fee)
|
|
7
|
+
*
|
|
8
|
+
* Requirements:
|
|
9
|
+
* - Node.js v22+
|
|
10
|
+
* - Breez API key (free, request at https://breez.technology/sdk/)
|
|
11
|
+
* - 12-word mnemonic for self-custody
|
|
12
|
+
*/
|
|
13
|
+
import type { Deposit } from '../../types/index.js';
|
|
14
|
+
export interface BreezPaymentRequest {
|
|
15
|
+
amount: number;
|
|
16
|
+
agentId: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface BreezPaymentResponse {
|
|
20
|
+
success: boolean;
|
|
21
|
+
deposit?: Partial<Deposit>;
|
|
22
|
+
invoice?: {
|
|
23
|
+
bolt11: string;
|
|
24
|
+
amountSats: number;
|
|
25
|
+
expiresAt: Date;
|
|
26
|
+
};
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Convert USD to sats
|
|
31
|
+
*/
|
|
32
|
+
declare function usdToSats(usd: number): number;
|
|
33
|
+
/**
|
|
34
|
+
* Convert sats to USD
|
|
35
|
+
*/
|
|
36
|
+
declare function satsToUsd(sats: number): number;
|
|
37
|
+
/**
|
|
38
|
+
* Create a Lightning invoice for BTC deposit
|
|
39
|
+
*/
|
|
40
|
+
export declare function createBreezDeposit(request: BreezPaymentRequest): Promise<BreezPaymentResponse>;
|
|
41
|
+
/**
|
|
42
|
+
* Send Lightning payment (for withdrawals)
|
|
43
|
+
*/
|
|
44
|
+
export declare function sendBreezPayment(destination: string, // bolt11 invoice or Lightning Address
|
|
45
|
+
amountUsd: number): Promise<{
|
|
46
|
+
success: boolean;
|
|
47
|
+
txId?: string;
|
|
48
|
+
error?: string;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Get wallet balance
|
|
52
|
+
*/
|
|
53
|
+
export declare function getWalletBalance(): Promise<{
|
|
54
|
+
success: boolean;
|
|
55
|
+
balanceSats?: number;
|
|
56
|
+
balanceUsd?: number;
|
|
57
|
+
error?: string;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* List recent payments
|
|
61
|
+
*/
|
|
62
|
+
export declare function listPayments(limit?: number): Promise<{
|
|
63
|
+
success: boolean;
|
|
64
|
+
payments?: any[];
|
|
65
|
+
error?: string;
|
|
66
|
+
}>;
|
|
67
|
+
/**
|
|
68
|
+
* Disconnect from SDK (cleanup)
|
|
69
|
+
*/
|
|
70
|
+
export declare function disconnect(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Generate a new mnemonic (for initial setup)
|
|
73
|
+
*/
|
|
74
|
+
export declare function generateMnemonic(): string;
|
|
75
|
+
export declare const breezService: {
|
|
76
|
+
createDeposit: typeof createBreezDeposit;
|
|
77
|
+
sendPayment: typeof sendBreezPayment;
|
|
78
|
+
getWalletBalance: typeof getWalletBalance;
|
|
79
|
+
listPayments: typeof listPayments;
|
|
80
|
+
disconnect: typeof disconnect;
|
|
81
|
+
usdToSats: typeof usdToSats;
|
|
82
|
+
satsToUsd: typeof satsToUsd;
|
|
83
|
+
config: {
|
|
84
|
+
configured: boolean;
|
|
85
|
+
apiKeySet: boolean;
|
|
86
|
+
mnemonicSet: boolean;
|
|
87
|
+
network: string;
|
|
88
|
+
satsPerUsd: number;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Breez SDK Payment Service - Bitcoin on Lightning (Nodeless/Liquid)
|
|
3
|
+
*
|
|
4
|
+
* Uses Breez SDK Liquid for self-custodial Lightning payments.
|
|
5
|
+
* Docs: https://sdk-doc-liquid.breez.technology/
|
|
6
|
+
* Fee: Network fees only (no platform fee)
|
|
7
|
+
*
|
|
8
|
+
* Requirements:
|
|
9
|
+
* - Node.js v22+
|
|
10
|
+
* - Breez API key (free, request at https://breez.technology/sdk/)
|
|
11
|
+
* - 12-word mnemonic for self-custody
|
|
12
|
+
*/
|
|
13
|
+
// Configuration
|
|
14
|
+
const BREEZ_API_KEY = process.env.BREEZ_API_KEY || '';
|
|
15
|
+
const BREEZ_MNEMONIC = process.env.BREEZ_MNEMONIC || '';
|
|
16
|
+
const BREEZ_WORKING_DIR = process.env.BREEZ_WORKING_DIR || './breez-data';
|
|
17
|
+
const BREEZ_NETWORK = process.env.BREEZ_NETWORK || 'mainnet'; // 'mainnet' or 'testnet'
|
|
18
|
+
// Exchange rate (sats per USD) - in production, fetch from API
|
|
19
|
+
const SATS_PER_USD = parseInt(process.env.BREEZ_SATS_PER_USD || '1000', 10);
|
|
20
|
+
// SDK instance (lazy loaded)
|
|
21
|
+
let sdkInstance = null;
|
|
22
|
+
let sdkInitPromise = null;
|
|
23
|
+
/**
|
|
24
|
+
* Convert USD to sats
|
|
25
|
+
*/
|
|
26
|
+
function usdToSats(usd) {
|
|
27
|
+
return Math.floor(usd * SATS_PER_USD);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Convert sats to USD
|
|
31
|
+
*/
|
|
32
|
+
function satsToUsd(sats) {
|
|
33
|
+
return sats / SATS_PER_USD;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Initialize and connect to Breez SDK
|
|
37
|
+
*/
|
|
38
|
+
async function getSDK() {
|
|
39
|
+
if (sdkInstance) {
|
|
40
|
+
return sdkInstance;
|
|
41
|
+
}
|
|
42
|
+
if (sdkInitPromise) {
|
|
43
|
+
return sdkInitPromise;
|
|
44
|
+
}
|
|
45
|
+
if (!BREEZ_API_KEY) {
|
|
46
|
+
throw new Error('BREEZ_API_KEY not configured. Request one at https://breez.technology/sdk/');
|
|
47
|
+
}
|
|
48
|
+
if (!BREEZ_MNEMONIC) {
|
|
49
|
+
throw new Error('BREEZ_MNEMONIC not configured. Generate a 12-word mnemonic for self-custody.');
|
|
50
|
+
}
|
|
51
|
+
sdkInitPromise = (async () => {
|
|
52
|
+
try {
|
|
53
|
+
// Dynamic import for the Breez SDK
|
|
54
|
+
const breezModule = await import('@breeztech/breez-sdk-liquid');
|
|
55
|
+
// Network type is a string literal: "mainnet" | "testnet" | "regtest"
|
|
56
|
+
const network = BREEZ_NETWORK;
|
|
57
|
+
const config = breezModule.defaultConfig(network, BREEZ_API_KEY);
|
|
58
|
+
config.workingDir = BREEZ_WORKING_DIR;
|
|
59
|
+
sdkInstance = await breezModule.connect({
|
|
60
|
+
mnemonic: BREEZ_MNEMONIC,
|
|
61
|
+
config,
|
|
62
|
+
});
|
|
63
|
+
return sdkInstance;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
sdkInitPromise = null;
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
})();
|
|
70
|
+
return sdkInitPromise;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Create a Lightning invoice for BTC deposit
|
|
74
|
+
*/
|
|
75
|
+
export async function createBreezDeposit(request) {
|
|
76
|
+
if (!BREEZ_API_KEY || !BREEZ_MNEMONIC) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: !BREEZ_API_KEY
|
|
80
|
+
? 'BREEZ_API_KEY not configured. Request one at https://breez.technology/sdk/'
|
|
81
|
+
: 'BREEZ_MNEMONIC not configured. Set a 12-word mnemonic for self-custody.',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const sdk = await getSDK();
|
|
86
|
+
const amountSats = usdToSats(request.amount);
|
|
87
|
+
// Fetch limits first
|
|
88
|
+
const limits = await sdk.fetchLightningLimits();
|
|
89
|
+
if (amountSats < limits.receive.minSat) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: `Minimum deposit: ${limits.receive.minSat} sats (~$${satsToUsd(limits.receive.minSat).toFixed(2)})`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (amountSats > limits.receive.maxSat) {
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
error: `Maximum deposit: ${limits.receive.maxSat} sats (~$${satsToUsd(limits.receive.maxSat).toFixed(2)})`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// Prepare the receive payment
|
|
102
|
+
const prepareResponse = await sdk.prepareReceivePayment({
|
|
103
|
+
paymentMethod: 'bolt11Invoice',
|
|
104
|
+
amount: {
|
|
105
|
+
type: 'bitcoin',
|
|
106
|
+
payerAmountSat: amountSats,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
// Create the invoice
|
|
110
|
+
const description = request.description || `Clawdentials deposit for ${request.agentId}`;
|
|
111
|
+
const result = await sdk.receivePayment({
|
|
112
|
+
prepareResponse,
|
|
113
|
+
description,
|
|
114
|
+
});
|
|
115
|
+
// Invoice expires in 1 hour typically
|
|
116
|
+
const expiresAt = new Date(Date.now() + 60 * 60 * 1000);
|
|
117
|
+
return {
|
|
118
|
+
success: true,
|
|
119
|
+
deposit: {
|
|
120
|
+
id: `breez_${Date.now()}_${Math.random().toString(36).substring(7)}`,
|
|
121
|
+
agentId: request.agentId,
|
|
122
|
+
amount: request.amount,
|
|
123
|
+
currency: 'BTC',
|
|
124
|
+
network: 'lightning',
|
|
125
|
+
status: 'pending',
|
|
126
|
+
provider: 'breez',
|
|
127
|
+
externalId: null,
|
|
128
|
+
paymentAddress: result.destination, // bolt11 invoice
|
|
129
|
+
paymentUrl: null,
|
|
130
|
+
createdAt: new Date(),
|
|
131
|
+
expiresAt,
|
|
132
|
+
completedAt: null,
|
|
133
|
+
txHash: null,
|
|
134
|
+
},
|
|
135
|
+
invoice: {
|
|
136
|
+
bolt11: result.destination,
|
|
137
|
+
amountSats,
|
|
138
|
+
expiresAt,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
error: error instanceof Error ? error.message : 'Failed to create Lightning invoice',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Send Lightning payment (for withdrawals)
|
|
151
|
+
*/
|
|
152
|
+
export async function sendBreezPayment(destination, // bolt11 invoice or Lightning Address
|
|
153
|
+
amountUsd) {
|
|
154
|
+
if (!BREEZ_API_KEY || !BREEZ_MNEMONIC) {
|
|
155
|
+
return { success: false, error: 'Breez SDK not configured' };
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const sdk = await getSDK();
|
|
159
|
+
// Prepare the payment
|
|
160
|
+
const prepareResponse = await sdk.prepareSendPayment({
|
|
161
|
+
destination,
|
|
162
|
+
});
|
|
163
|
+
// Check fees are acceptable
|
|
164
|
+
const feesSat = prepareResponse.feesSat;
|
|
165
|
+
console.log(`Breez payment fees: ${feesSat} sats`);
|
|
166
|
+
// Send the payment
|
|
167
|
+
const result = await sdk.sendPayment({
|
|
168
|
+
prepareResponse,
|
|
169
|
+
});
|
|
170
|
+
return {
|
|
171
|
+
success: true,
|
|
172
|
+
txId: result.payment?.txId || result.payment?.id,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
return {
|
|
177
|
+
success: false,
|
|
178
|
+
error: error instanceof Error ? error.message : 'Failed to send payment',
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get wallet balance
|
|
184
|
+
*/
|
|
185
|
+
export async function getWalletBalance() {
|
|
186
|
+
if (!BREEZ_API_KEY || !BREEZ_MNEMONIC) {
|
|
187
|
+
return { success: false, error: 'Breez SDK not configured' };
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
const sdk = await getSDK();
|
|
191
|
+
const info = await sdk.getInfo();
|
|
192
|
+
return {
|
|
193
|
+
success: true,
|
|
194
|
+
balanceSats: info.balanceSat,
|
|
195
|
+
balanceUsd: satsToUsd(info.balanceSat),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
return {
|
|
200
|
+
success: false,
|
|
201
|
+
error: error instanceof Error ? error.message : 'Failed to get balance',
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* List recent payments
|
|
207
|
+
*/
|
|
208
|
+
export async function listPayments(limit = 10) {
|
|
209
|
+
if (!BREEZ_API_KEY || !BREEZ_MNEMONIC) {
|
|
210
|
+
return { success: false, error: 'Breez SDK not configured' };
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const sdk = await getSDK();
|
|
214
|
+
const payments = await sdk.listPayments({
|
|
215
|
+
limit,
|
|
216
|
+
});
|
|
217
|
+
return {
|
|
218
|
+
success: true,
|
|
219
|
+
payments,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
return {
|
|
224
|
+
success: false,
|
|
225
|
+
error: error instanceof Error ? error.message : 'Failed to list payments',
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Disconnect from SDK (cleanup)
|
|
231
|
+
*/
|
|
232
|
+
export async function disconnect() {
|
|
233
|
+
if (sdkInstance) {
|
|
234
|
+
try {
|
|
235
|
+
await sdkInstance.disconnect();
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
// Ignore disconnect errors
|
|
239
|
+
}
|
|
240
|
+
sdkInstance = null;
|
|
241
|
+
sdkInitPromise = null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Generate a new mnemonic (for initial setup)
|
|
246
|
+
*/
|
|
247
|
+
export function generateMnemonic() {
|
|
248
|
+
// In production, use a proper BIP39 library
|
|
249
|
+
// This is a placeholder - the actual mnemonic should be generated securely
|
|
250
|
+
throw new Error('Generate mnemonic using a BIP39 library or wallet. Do not use this in production.');
|
|
251
|
+
}
|
|
252
|
+
export const breezService = {
|
|
253
|
+
createDeposit: createBreezDeposit,
|
|
254
|
+
sendPayment: sendBreezPayment,
|
|
255
|
+
getWalletBalance,
|
|
256
|
+
listPayments,
|
|
257
|
+
disconnect,
|
|
258
|
+
usdToSats,
|
|
259
|
+
satsToUsd,
|
|
260
|
+
config: {
|
|
261
|
+
configured: !!(BREEZ_API_KEY && BREEZ_MNEMONIC),
|
|
262
|
+
apiKeySet: !!BREEZ_API_KEY,
|
|
263
|
+
mnemonicSet: !!BREEZ_MNEMONIC,
|
|
264
|
+
network: BREEZ_NETWORK,
|
|
265
|
+
satsPerUsd: SATS_PER_USD,
|
|
266
|
+
},
|
|
267
|
+
};
|