@profullstack/coinpay 0.3.9 → 0.4.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@profullstack/coinpay",
3
- "version": "0.3.9",
4
- "description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) in your Node.js application",
3
+ "version": "0.4.0",
4
+ "description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet and swap support",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./src/index.d.ts",
@@ -20,6 +20,14 @@
20
20
  "./webhooks": {
21
21
  "import": "./src/webhooks.js",
22
22
  "types": "./src/webhooks.d.ts"
23
+ },
24
+ "./wallet": {
25
+ "import": "./src/wallet.js",
26
+ "types": "./src/wallet.d.ts"
27
+ },
28
+ "./swap": {
29
+ "import": "./src/swap.js",
30
+ "types": "./src/swap.d.ts"
23
31
  }
24
32
  },
25
33
  "files": [
@@ -49,12 +57,16 @@
49
57
  "stablecoin",
50
58
  "non-custodial",
51
59
  "wallet",
60
+ "swap",
61
+ "exchange",
52
62
  "sdk",
53
63
  "cli",
54
64
  "web3",
55
65
  "blockchain",
56
66
  "payment-gateway",
57
- "merchant"
67
+ "merchant",
68
+ "bip39",
69
+ "mnemonic"
58
70
  ],
59
71
  "author": "Profullstack, Inc.",
60
72
  "license": "MIT",
@@ -76,5 +88,10 @@
76
88
  "prettier": "^3.4.1"
77
89
  },
78
90
  "peerDependencies": {},
79
- "dependencies": {}
91
+ "dependencies": {
92
+ "@scure/bip39": "^1.4.0",
93
+ "@scure/bip32": "^1.5.0",
94
+ "@noble/curves": "^1.6.0",
95
+ "@noble/hashes": "^1.5.0"
96
+ }
80
97
  }
package/src/client.js CHANGED
@@ -396,6 +396,93 @@ export class CoinPayClient {
396
396
  }),
397
397
  });
398
398
  }
399
+
400
+ // ── Escrow Methods ──────────────────────────────────────
401
+
402
+ /**
403
+ * Create a new escrow
404
+ * @param {Object} params - See escrow.js createEscrow for full params
405
+ * @returns {Promise<Object>} Created escrow with releaseToken
406
+ */
407
+ async createEscrow(params) {
408
+ const { createEscrow } = await import('./escrow.js');
409
+ return createEscrow(this, params);
410
+ }
411
+
412
+ /**
413
+ * Get escrow status
414
+ * @param {string} escrowId
415
+ * @returns {Promise<Object>}
416
+ */
417
+ async getEscrow(escrowId) {
418
+ const { getEscrow } = await import('./escrow.js');
419
+ return getEscrow(this, escrowId);
420
+ }
421
+
422
+ /**
423
+ * List escrows with filters
424
+ * @param {Object} [filters]
425
+ * @returns {Promise<Object>}
426
+ */
427
+ async listEscrows(filters) {
428
+ const { listEscrows } = await import('./escrow.js');
429
+ return listEscrows(this, filters);
430
+ }
431
+
432
+ /**
433
+ * Release escrow funds to beneficiary
434
+ * @param {string} escrowId
435
+ * @param {string} releaseToken
436
+ * @returns {Promise<Object>}
437
+ */
438
+ async releaseEscrow(escrowId, releaseToken) {
439
+ const { releaseEscrow } = await import('./escrow.js');
440
+ return releaseEscrow(this, escrowId, releaseToken);
441
+ }
442
+
443
+ /**
444
+ * Refund escrow to depositor
445
+ * @param {string} escrowId
446
+ * @param {string} releaseToken
447
+ * @returns {Promise<Object>}
448
+ */
449
+ async refundEscrow(escrowId, releaseToken) {
450
+ const { refundEscrow } = await import('./escrow.js');
451
+ return refundEscrow(this, escrowId, releaseToken);
452
+ }
453
+
454
+ /**
455
+ * Dispute an escrow
456
+ * @param {string} escrowId
457
+ * @param {string} token - release_token or beneficiary_token
458
+ * @param {string} reason - At least 10 characters
459
+ * @returns {Promise<Object>}
460
+ */
461
+ async disputeEscrow(escrowId, token, reason) {
462
+ const { disputeEscrow } = await import('./escrow.js');
463
+ return disputeEscrow(this, escrowId, token, reason);
464
+ }
465
+
466
+ /**
467
+ * Get escrow audit log
468
+ * @param {string} escrowId
469
+ * @returns {Promise<Array>}
470
+ */
471
+ async getEscrowEvents(escrowId) {
472
+ const { getEscrowEvents } = await import('./escrow.js');
473
+ return getEscrowEvents(this, escrowId);
474
+ }
475
+
476
+ /**
477
+ * Poll escrow until target status
478
+ * @param {string} escrowId
479
+ * @param {Object} [options] - { targetStatus, intervalMs, timeoutMs }
480
+ * @returns {Promise<Object>}
481
+ */
482
+ async waitForEscrow(escrowId, options) {
483
+ const { waitForEscrow } = await import('./escrow.js');
484
+ return waitForEscrow(this, escrowId, options);
485
+ }
399
486
  }
400
487
 
401
488
  export default CoinPayClient;
package/src/escrow.js ADDED
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Escrow SDK Module
3
+ *
4
+ * Anonymous, non-custodial escrow for crypto payments.
5
+ * Both humans and AI agents can create/fund/release/dispute escrows.
6
+ *
7
+ * @example
8
+ * import { CoinPayClient } from '@profullstack/coinpay';
9
+ *
10
+ * const client = new CoinPayClient({ apiKey: 'your-key' });
11
+ *
12
+ * // Create escrow
13
+ * const escrow = await client.createEscrow({
14
+ * chain: 'SOL',
15
+ * amount: 0.5,
16
+ * depositorAddress: 'depositor-wallet',
17
+ * beneficiaryAddress: 'worker-wallet',
18
+ * metadata: { job: 'Code review', deadline: '2026-02-10' }
19
+ * });
20
+ * // Save escrow.releaseToken — needed to release/refund
21
+ *
22
+ * // Check status
23
+ * const status = await client.getEscrow(escrow.id);
24
+ *
25
+ * // Release funds to worker
26
+ * await client.releaseEscrow(escrow.id, escrow.releaseToken);
27
+ */
28
+
29
+ /**
30
+ * Create a new escrow
31
+ * @param {CoinPayClient} client - API client instance
32
+ * @param {Object} params - Escrow parameters
33
+ * @param {string} params.chain - Blockchain (BTC, ETH, SOL, POL, etc.)
34
+ * @param {number} params.amount - Crypto amount to escrow
35
+ * @param {string} params.depositorAddress - Wallet address for refunds
36
+ * @param {string} params.beneficiaryAddress - Wallet address for releases
37
+ * @param {string} [params.arbiterAddress] - Optional dispute resolver address
38
+ * @param {Object} [params.metadata] - Job details, milestones, etc.
39
+ * @param {number} [params.expiresInHours] - Deposit window (default: 24h)
40
+ * @returns {Promise<Object>} Created escrow with releaseToken and beneficiaryToken
41
+ */
42
+ export async function createEscrow(client, {
43
+ chain,
44
+ amount,
45
+ depositorAddress,
46
+ beneficiaryAddress,
47
+ arbiterAddress,
48
+ metadata,
49
+ expiresInHours,
50
+ }) {
51
+ const body = {
52
+ chain,
53
+ amount,
54
+ depositor_address: depositorAddress,
55
+ beneficiary_address: beneficiaryAddress,
56
+ };
57
+ if (arbiterAddress) body.arbiter_address = arbiterAddress;
58
+ if (metadata) body.metadata = metadata;
59
+ if (expiresInHours) body.expires_in_hours = expiresInHours;
60
+
61
+ const data = await client.request('/escrow', {
62
+ method: 'POST',
63
+ body: JSON.stringify(body),
64
+ });
65
+
66
+ return {
67
+ id: data.id,
68
+ escrowAddress: data.escrow_address,
69
+ chain: data.chain,
70
+ amount: data.amount,
71
+ amountUsd: data.amount_usd,
72
+ status: data.status,
73
+ depositorAddress: data.depositor_address,
74
+ beneficiaryAddress: data.beneficiary_address,
75
+ releaseToken: data.release_token,
76
+ beneficiaryToken: data.beneficiary_token,
77
+ metadata: data.metadata,
78
+ expiresAt: data.expires_at,
79
+ createdAt: data.created_at,
80
+ };
81
+ }
82
+
83
+ /**
84
+ * Get escrow status
85
+ * @param {CoinPayClient} client
86
+ * @param {string} escrowId
87
+ * @returns {Promise<Object>} Escrow status (public view, no tokens)
88
+ */
89
+ export async function getEscrow(client, escrowId) {
90
+ const data = await client.request(`/escrow/${escrowId}`);
91
+ return normalizeEscrow(data);
92
+ }
93
+
94
+ /**
95
+ * List escrows with filters
96
+ * @param {CoinPayClient} client
97
+ * @param {Object} [filters]
98
+ * @param {string} [filters.status] - Filter by status
99
+ * @param {string} [filters.depositor] - Filter by depositor address
100
+ * @param {string} [filters.beneficiary] - Filter by beneficiary address
101
+ * @param {number} [filters.limit] - Results per page (default: 20)
102
+ * @param {number} [filters.offset] - Offset for pagination
103
+ * @returns {Promise<Object>} { escrows, total, limit, offset }
104
+ */
105
+ export async function listEscrows(client, filters = {}) {
106
+ const params = new URLSearchParams();
107
+ if (filters.status) params.set('status', filters.status);
108
+ if (filters.depositor) params.set('depositor', filters.depositor);
109
+ if (filters.beneficiary) params.set('beneficiary', filters.beneficiary);
110
+ if (filters.limit) params.set('limit', String(filters.limit));
111
+ if (filters.offset) params.set('offset', String(filters.offset));
112
+
113
+ const data = await client.request(`/escrow?${params.toString()}`);
114
+ return {
115
+ escrows: (data.escrows || []).map(normalizeEscrow),
116
+ total: data.total,
117
+ limit: data.limit,
118
+ offset: data.offset,
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Release escrow funds to beneficiary
124
+ * @param {CoinPayClient} client
125
+ * @param {string} escrowId
126
+ * @param {string} releaseToken - Secret token from escrow creation
127
+ * @returns {Promise<Object>} Updated escrow
128
+ */
129
+ export async function releaseEscrow(client, escrowId, releaseToken) {
130
+ const data = await client.request(`/escrow/${escrowId}/release`, {
131
+ method: 'POST',
132
+ body: JSON.stringify({ release_token: releaseToken }),
133
+ });
134
+ return normalizeEscrow(data);
135
+ }
136
+
137
+ /**
138
+ * Refund escrow to depositor
139
+ * @param {CoinPayClient} client
140
+ * @param {string} escrowId
141
+ * @param {string} releaseToken
142
+ * @returns {Promise<Object>} Updated escrow
143
+ */
144
+ export async function refundEscrow(client, escrowId, releaseToken) {
145
+ const data = await client.request(`/escrow/${escrowId}/refund`, {
146
+ method: 'POST',
147
+ body: JSON.stringify({ release_token: releaseToken }),
148
+ });
149
+ return normalizeEscrow(data);
150
+ }
151
+
152
+ /**
153
+ * Dispute an escrow
154
+ * @param {CoinPayClient} client
155
+ * @param {string} escrowId
156
+ * @param {string} token - release_token or beneficiary_token
157
+ * @param {string} reason - Dispute reason (min 10 chars)
158
+ * @returns {Promise<Object>} Updated escrow
159
+ */
160
+ export async function disputeEscrow(client, escrowId, token, reason) {
161
+ const data = await client.request(`/escrow/${escrowId}/dispute`, {
162
+ method: 'POST',
163
+ body: JSON.stringify({ token, reason }),
164
+ });
165
+ return normalizeEscrow(data);
166
+ }
167
+
168
+ /**
169
+ * Get escrow event log
170
+ * @param {CoinPayClient} client
171
+ * @param {string} escrowId
172
+ * @returns {Promise<Array>} Array of events
173
+ */
174
+ export async function getEscrowEvents(client, escrowId) {
175
+ const data = await client.request(`/escrow/${escrowId}/events`);
176
+ return (data.events || []).map(e => ({
177
+ id: e.id,
178
+ escrowId: e.escrow_id,
179
+ eventType: e.event_type,
180
+ actor: e.actor,
181
+ details: e.details,
182
+ createdAt: e.created_at,
183
+ }));
184
+ }
185
+
186
+ /**
187
+ * Poll escrow until it reaches a target status
188
+ * @param {CoinPayClient} client
189
+ * @param {string} escrowId
190
+ * @param {Object} [options]
191
+ * @param {string} [options.targetStatus] - Status to wait for (default: 'funded')
192
+ * @param {number} [options.intervalMs] - Poll interval (default: 10000)
193
+ * @param {number} [options.timeoutMs] - Max wait time (default: 3600000 = 1h)
194
+ * @returns {Promise<Object>} Escrow when target status reached
195
+ */
196
+ export async function waitForEscrow(client, escrowId, options = {}) {
197
+ const {
198
+ targetStatus = 'funded',
199
+ intervalMs = 10000,
200
+ timeoutMs = 3600000,
201
+ } = options;
202
+
203
+ const start = Date.now();
204
+
205
+ while (Date.now() - start < timeoutMs) {
206
+ const escrow = await getEscrow(client, escrowId);
207
+
208
+ if (escrow.status === targetStatus) return escrow;
209
+ if (['settled', 'refunded', 'expired'].includes(escrow.status)) return escrow;
210
+
211
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
212
+ }
213
+
214
+ throw new Error(`Escrow ${escrowId} did not reach status '${targetStatus}' within ${timeoutMs}ms`);
215
+ }
216
+
217
+ // ── Helpers ──
218
+
219
+ function normalizeEscrow(data) {
220
+ return {
221
+ id: data.id,
222
+ escrowAddress: data.escrow_address,
223
+ chain: data.chain,
224
+ amount: data.amount,
225
+ amountUsd: data.amount_usd,
226
+ feeAmount: data.fee_amount,
227
+ depositedAmount: data.deposited_amount,
228
+ status: data.status,
229
+ depositorAddress: data.depositor_address,
230
+ beneficiaryAddress: data.beneficiary_address,
231
+ arbiterAddress: data.arbiter_address,
232
+ depositTxHash: data.deposit_tx_hash,
233
+ settlementTxHash: data.settlement_tx_hash,
234
+ metadata: data.metadata,
235
+ disputeReason: data.dispute_reason,
236
+ disputeResolution: data.dispute_resolution,
237
+ createdAt: data.created_at,
238
+ fundedAt: data.funded_at,
239
+ releasedAt: data.released_at,
240
+ settledAt: data.settled_at,
241
+ disputedAt: data.disputed_at,
242
+ refundedAt: data.refunded_at,
243
+ expiresAt: data.expires_at,
244
+ };
245
+ }
package/src/index.d.ts CHANGED
@@ -5,9 +5,17 @@
5
5
  * @module @profullstack/coinpay
6
6
  */
7
7
 
8
+ // Client exports
8
9
  export { CoinPayClient } from './client.js';
9
- export type { CoinPayClientOptions, PaymentParams, ListPaymentsParams, WaitForPaymentOptions, CreateBusinessParams } from './client.js';
10
+ export type {
11
+ CoinPayClientOptions,
12
+ PaymentParams,
13
+ ListPaymentsParams,
14
+ WaitForPaymentOptions,
15
+ CreateBusinessParams
16
+ } from './client.js';
10
17
 
18
+ // Payment exports
11
19
  export {
12
20
  createPayment,
13
21
  getPayment,
@@ -17,8 +25,13 @@ export {
17
25
  PaymentStatus,
18
26
  FiatCurrency,
19
27
  } from './payments.js';
20
- export type { CreatePaymentParams, GetPaymentParams, ListPaymentsFnParams } from './payments.js';
28
+ export type {
29
+ CreatePaymentParams,
30
+ GetPaymentParams,
31
+ ListPaymentsFnParams
32
+ } from './payments.js';
21
33
 
34
+ // Webhook exports
22
35
  export {
23
36
  verifyWebhookSignature,
24
37
  generateWebhookSignature,
@@ -33,5 +46,55 @@ export type {
33
46
  ParsedWebhookEvent,
34
47
  } from './webhooks.js';
35
48
 
49
+ // Wallet exports
50
+ export {
51
+ WalletClient,
52
+ WalletChain,
53
+ DEFAULT_CHAINS,
54
+ generateMnemonic,
55
+ validateMnemonic,
56
+ getDerivationPath,
57
+ restoreFromBackup,
58
+ } from './wallet.js';
59
+ export type {
60
+ WalletChainType,
61
+ WalletCreateOptions,
62
+ WalletImportOptions,
63
+ WalletAddress,
64
+ AddressListResult,
65
+ WalletBalance,
66
+ SendOptions,
67
+ HistoryOptions,
68
+ Transaction,
69
+ FeeEstimate,
70
+ } from './wallet.js';
71
+
72
+ // Swap exports
73
+ export {
74
+ SwapClient,
75
+ SwapCoins,
76
+ SwapStatus,
77
+ getSwapCoins,
78
+ getSwapQuote,
79
+ createSwap,
80
+ getSwapStatus,
81
+ getSwapHistory,
82
+ } from './swap.js';
83
+ export type {
84
+ SwapStatusType,
85
+ SwapClientOptions,
86
+ CoinInfo,
87
+ CoinsResult,
88
+ SwapQuote,
89
+ QuoteResult,
90
+ CreateSwapParams,
91
+ Swap,
92
+ SwapResult,
93
+ WaitForSwapOptions,
94
+ SwapHistoryOptions,
95
+ SwapHistoryPagination,
96
+ SwapHistoryResult,
97
+ } from './swap.js';
98
+
36
99
  import { CoinPayClient } from './client.js';
37
100
  export default CoinPayClient;
package/src/index.js CHANGED
@@ -16,6 +16,24 @@
16
16
  * blockchain: Blockchain.BTC,
17
17
  * description: 'Order #12345'
18
18
  * });
19
+ *
20
+ * @example
21
+ * // Wallet usage
22
+ * import { WalletClient } from '@profullstack/coinpay';
23
+ *
24
+ * // Create a new wallet
25
+ * const wallet = await WalletClient.create({ words: 12, chains: ['BTC', 'ETH'] });
26
+ * console.log('Backup your seed:', wallet.getMnemonic());
27
+ *
28
+ * // Or import existing
29
+ * const wallet = await WalletClient.fromSeed('your twelve word mnemonic phrase ...');
30
+ *
31
+ * @example
32
+ * // Swap usage
33
+ * import { SwapClient } from '@profullstack/coinpay';
34
+ *
35
+ * const swap = new SwapClient({ walletId: 'your-wallet-id' });
36
+ * const quote = await swap.getSwapQuote('BTC', 'ETH', 0.1);
19
37
  */
20
38
 
21
39
  import { CoinPayClient } from './client.js';
@@ -36,6 +54,40 @@ import {
36
54
  WebhookEvent,
37
55
  } from './webhooks.js';
38
56
 
57
+ import {
58
+ createEscrow,
59
+ getEscrow,
60
+ listEscrows,
61
+ releaseEscrow,
62
+ refundEscrow,
63
+ disputeEscrow,
64
+ getEscrowEvents,
65
+ waitForEscrow,
66
+ } from './escrow.js';
67
+
68
+ // Wallet exports
69
+ import {
70
+ WalletClient,
71
+ WalletChain,
72
+ DEFAULT_CHAINS,
73
+ generateMnemonic,
74
+ validateMnemonic,
75
+ getDerivationPath,
76
+ restoreFromBackup,
77
+ } from './wallet.js';
78
+
79
+ // Swap exports
80
+ import {
81
+ SwapClient,
82
+ SwapCoins,
83
+ SwapStatus,
84
+ getSwapCoins,
85
+ getSwapQuote,
86
+ createSwap,
87
+ getSwapStatus,
88
+ getSwapHistory,
89
+ } from './swap.js';
90
+
39
91
  export {
40
92
  // Client
41
93
  CoinPayClient,
@@ -45,6 +97,35 @@ export {
45
97
  getPayment,
46
98
  listPayments,
47
99
 
100
+ // Escrow functions
101
+ createEscrow,
102
+ getEscrow,
103
+ listEscrows,
104
+ releaseEscrow,
105
+ refundEscrow,
106
+ disputeEscrow,
107
+ getEscrowEvents,
108
+ waitForEscrow,
109
+
110
+ // Wallet
111
+ WalletClient,
112
+ WalletChain,
113
+ DEFAULT_CHAINS,
114
+ generateMnemonic,
115
+ validateMnemonic,
116
+ getDerivationPath,
117
+ restoreFromBackup,
118
+
119
+ // Swap
120
+ SwapClient,
121
+ SwapCoins,
122
+ SwapStatus,
123
+ getSwapCoins,
124
+ getSwapQuote,
125
+ createSwap,
126
+ getSwapStatus,
127
+ getSwapHistory,
128
+
48
129
  // Constants
49
130
  Blockchain,
50
131
  Cryptocurrency, // Deprecated, use Blockchain
@@ -59,4 +140,4 @@ export {
59
140
  WebhookEvent,
60
141
  };
61
142
 
62
- export default CoinPayClient;
143
+ export default CoinPayClient;