paytaca-cli 0.2.0 → 0.3.1
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 +63 -2
- package/dist/commands/check.d.ts +14 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +162 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/claude.d.ts +9 -0
- package/dist/commands/claude.d.ts.map +1 -0
- package/dist/commands/claude.js +20 -0
- package/dist/commands/claude.js.map +1 -0
- package/dist/commands/opencode.d.ts +9 -0
- package/dist/commands/opencode.d.ts.map +1 -0
- package/dist/commands/opencode.js +20 -0
- package/dist/commands/opencode.js.map +1 -0
- package/dist/commands/pay.d.ts +17 -0
- package/dist/commands/pay.d.ts.map +1 -0
- package/dist/commands/pay.js +350 -0
- package/dist/commands/pay.js.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/types/x402.d.ts +72 -0
- package/dist/types/x402.d.ts.map +1 -0
- package/dist/types/x402.js +9 -0
- package/dist/types/x402.js.map +1 -0
- package/dist/utils/skill.d.ts +17 -0
- package/dist/utils/skill.d.ts.map +1 -0
- package/dist/utils/skill.js +100 -0
- package/dist/utils/skill.js.map +1 -0
- package/dist/utils/x402.d.ts +17 -0
- package/dist/utils/x402.d.ts.map +1 -0
- package/dist/utils/x402.js +119 -0
- package/dist/utils/x402.js.map +1 -0
- package/dist/utils/x402.test.d.ts +2 -0
- package/dist/utils/x402.test.d.ts.map +1 -0
- package/dist/utils/x402.test.js +216 -0
- package/dist/utils/x402.test.js.map +1 -0
- package/dist/wallet/x402.d.ts +29 -0
- package/dist/wallet/x402.d.ts.map +1 -0
- package/dist/wallet/x402.js +45 -0
- package/dist/wallet/x402.js.map +1 -0
- package/package.json +7 -2
- package/skills/paytaca/SKILL.md +130 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../../src/utils/x402.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,aAAa,EAEb,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAA;AAEjE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,GAAG,GAAG,eAAe,GAAG,IAAI,CA6B1E;AAED,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,eAAe,EAC7B,aAAa,EAAE,SAAS,GAAG,SAAS,GACnC,mBAAmB,GAAG,IAAI,CAQ5B;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,mBAAmB,EAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,cAAc,CAwBhB;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,mBAAmB,EAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,aAAa,CASf;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,UAAU,GAAE,OAAc,GACzB,MAAM,CAUR;AAED,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAChD,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,GAAG,cAAc,CAiB9D"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 utility functions for BCH payments
|
|
3
|
+
* Implements x402-bch v2.2 specification
|
|
4
|
+
* https://github.com/x402-bch/x402-bch/blob/master/specs/x402-bch-specification-v2.2.md
|
|
5
|
+
*/
|
|
6
|
+
import crypto from 'crypto';
|
|
7
|
+
import { BCH_ASSET_ID, BCH_MAINNET_NETWORK, BCH_CHIPNET_NETWORK, } from '../types/x402.js';
|
|
8
|
+
import { secp256k1 } from '@bitauth/libauth';
|
|
9
|
+
export { BCH_MAINNET_NETWORK, BCH_CHIPNET_NETWORK, BCH_ASSET_ID };
|
|
10
|
+
export function isBchNetwork(network) {
|
|
11
|
+
return network === BCH_MAINNET_NETWORK || network === BCH_CHIPNET_NETWORK;
|
|
12
|
+
}
|
|
13
|
+
export function isChipnetNetwork(network) {
|
|
14
|
+
return network === BCH_CHIPNET_NETWORK;
|
|
15
|
+
}
|
|
16
|
+
export function parsePaymentRequiredJson(body) {
|
|
17
|
+
if (!body || typeof body !== 'object')
|
|
18
|
+
return null;
|
|
19
|
+
if (body.x402Version !== 2)
|
|
20
|
+
return null;
|
|
21
|
+
const pr = {
|
|
22
|
+
x402Version: body.x402Version,
|
|
23
|
+
error: body.error,
|
|
24
|
+
resource: body.resource || { url: '' },
|
|
25
|
+
accepts: [],
|
|
26
|
+
extensions: body.extensions || {},
|
|
27
|
+
};
|
|
28
|
+
if (Array.isArray(body.accepts)) {
|
|
29
|
+
for (const accept of body.accepts) {
|
|
30
|
+
if (accept.scheme && accept.network && accept.payTo) {
|
|
31
|
+
pr.accepts.push({
|
|
32
|
+
scheme: accept.scheme,
|
|
33
|
+
network: accept.network,
|
|
34
|
+
amount: accept.amount,
|
|
35
|
+
asset: accept.asset || BCH_ASSET_ID,
|
|
36
|
+
payTo: accept.payTo,
|
|
37
|
+
maxTimeoutSeconds: accept.maxTimeoutSeconds || 60,
|
|
38
|
+
extra: accept.extra || {},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return pr;
|
|
44
|
+
}
|
|
45
|
+
export function selectBchPaymentRequirements(requirements, clientNetwork) {
|
|
46
|
+
const clientNetworkId = clientNetwork === 'chipnet' ? BCH_CHIPNET_NETWORK : BCH_MAINNET_NETWORK;
|
|
47
|
+
for (const accept of requirements.accepts) {
|
|
48
|
+
if (accept.scheme === 'utxo' && accept.network === clientNetworkId) {
|
|
49
|
+
return accept;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
export function buildPaymentPayload(accepted, resourceUrl, payer, txid, vout, amount) {
|
|
55
|
+
const resource = {
|
|
56
|
+
url: resourceUrl,
|
|
57
|
+
description: '',
|
|
58
|
+
mimeType: 'application/json',
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
x402Version: 2,
|
|
62
|
+
resource,
|
|
63
|
+
accepted,
|
|
64
|
+
payload: {
|
|
65
|
+
signature: '',
|
|
66
|
+
authorization: {
|
|
67
|
+
from: payer,
|
|
68
|
+
to: accepted.payTo,
|
|
69
|
+
value: accepted.amount,
|
|
70
|
+
txid,
|
|
71
|
+
vout,
|
|
72
|
+
amount,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
extensions: {},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function buildAuthorization(accepted, resourceUrl, payer, txid, vout, amount) {
|
|
79
|
+
return {
|
|
80
|
+
from: payer,
|
|
81
|
+
to: accepted.payTo,
|
|
82
|
+
value: accepted.amount,
|
|
83
|
+
txid,
|
|
84
|
+
vout,
|
|
85
|
+
amount,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function signMessageBCH(message, privateKeyHex, compressed = true) {
|
|
89
|
+
const prefix = '\x18Bitcoin Signed Message:\n';
|
|
90
|
+
const messageBytes = Buffer.from(message, 'utf8');
|
|
91
|
+
const prefixBytes = Buffer.from(prefix, 'utf8');
|
|
92
|
+
const lengthByte = Buffer.from([messageBytes.length]);
|
|
93
|
+
const prefixedMessage = Buffer.concat([prefixBytes, lengthByte, messageBytes]);
|
|
94
|
+
const hash = crypto.createHash('sha256').update(crypto.createHash('sha256').update(prefixedMessage).digest()).digest();
|
|
95
|
+
const privateKey = Buffer.from(privateKeyHex, 'hex');
|
|
96
|
+
const signature = secp256k1.signMessageHashDER(hash, privateKey);
|
|
97
|
+
return Buffer.from(signature).toString('base64');
|
|
98
|
+
}
|
|
99
|
+
export async function signAuthorization(authorization, signMessage) {
|
|
100
|
+
const message = JSON.stringify(authorization);
|
|
101
|
+
return signMessage(message);
|
|
102
|
+
}
|
|
103
|
+
export function parsePaymentResponse(data) {
|
|
104
|
+
if (!data)
|
|
105
|
+
return { isValid: false, invalidReason: 'no_response_data' };
|
|
106
|
+
if (typeof data.isValid === 'boolean') {
|
|
107
|
+
return {
|
|
108
|
+
isValid: data.isValid,
|
|
109
|
+
payer: data.payer,
|
|
110
|
+
invalidReason: data.invalidReason,
|
|
111
|
+
remainingBalanceSat: data.remainingBalanceSat,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (data.error) {
|
|
115
|
+
return { isValid: false, invalidReason: data.error };
|
|
116
|
+
}
|
|
117
|
+
return { isValid: false, invalidReason: 'unknown_response_format' };
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=x402.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.js","sourceRoot":"","sources":["../../src/utils/x402.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.test.d.ts","sourceRoot":"","sources":["../../src/utils/x402.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { parsePaymentRequiredJson, selectBchPaymentRequirements, buildPaymentPayload, buildAuthorization, parsePaymentResponse, isBchNetwork, isChipnetNetwork, BCH_MAINNET_NETWORK, BCH_CHIPNET_NETWORK, BCH_ASSET_ID, } from './x402.js';
|
|
3
|
+
describe('x402 parsing', () => {
|
|
4
|
+
describe('parsePaymentRequiredJson', () => {
|
|
5
|
+
it('should parse valid PaymentRequired JSON', () => {
|
|
6
|
+
const input = {
|
|
7
|
+
x402Version: 2,
|
|
8
|
+
error: 'Payment required',
|
|
9
|
+
resource: { url: 'https://api.example.com/data' },
|
|
10
|
+
accepts: [
|
|
11
|
+
{
|
|
12
|
+
scheme: 'utxo',
|
|
13
|
+
network: BCH_MAINNET_NETWORK,
|
|
14
|
+
amount: '1000',
|
|
15
|
+
asset: BCH_ASSET_ID,
|
|
16
|
+
payTo: 'bitcoincash:qp2f5j6q3fj5gjwgk8rkq8xrk8q8q8q8q8q8q8q8q',
|
|
17
|
+
maxTimeoutSeconds: 300,
|
|
18
|
+
extra: {},
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
extensions: {},
|
|
22
|
+
};
|
|
23
|
+
const result = parsePaymentRequiredJson(input);
|
|
24
|
+
expect(result).not.toBeNull();
|
|
25
|
+
expect(result.x402Version).toBe(2);
|
|
26
|
+
expect(result.error).toBe('Payment required');
|
|
27
|
+
expect(result.resource.url).toBe('https://api.example.com/data');
|
|
28
|
+
expect(result.accepts).toHaveLength(1);
|
|
29
|
+
expect(result.accepts[0].scheme).toBe('utxo');
|
|
30
|
+
expect(result.accepts[0].amount).toBe('1000');
|
|
31
|
+
});
|
|
32
|
+
it('should return null for null input', () => {
|
|
33
|
+
expect(parsePaymentRequiredJson(null)).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
it('should return null for non-object input', () => {
|
|
36
|
+
expect(parsePaymentRequiredJson('string')).toBeNull();
|
|
37
|
+
expect(parsePaymentRequiredJson(123)).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
it('should return null for wrong x402Version', () => {
|
|
40
|
+
const input = { x402Version: 1, accepts: [] };
|
|
41
|
+
expect(parsePaymentRequiredJson(input)).toBeNull();
|
|
42
|
+
});
|
|
43
|
+
it('should use default values for missing optional fields', () => {
|
|
44
|
+
const input = {
|
|
45
|
+
x402Version: 2,
|
|
46
|
+
resource: {},
|
|
47
|
+
accepts: [
|
|
48
|
+
{
|
|
49
|
+
scheme: 'utxo',
|
|
50
|
+
network: BCH_MAINNET_NETWORK,
|
|
51
|
+
payTo: 'bitcoincash:qp2f5j6q3fj5gjwgk8rkq8xrk8q8q8q8q8q8q8q8',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
const result = parsePaymentRequiredJson(input);
|
|
56
|
+
expect(result).not.toBeNull();
|
|
57
|
+
expect(result.accepts[0].asset).toBe(BCH_ASSET_ID);
|
|
58
|
+
expect(result.accepts[0].maxTimeoutSeconds).toBe(60);
|
|
59
|
+
});
|
|
60
|
+
it('should filter out invalid accepts entries', () => {
|
|
61
|
+
const input = {
|
|
62
|
+
x402Version: 2,
|
|
63
|
+
resource: { url: 'https://api.example.com' },
|
|
64
|
+
accepts: [
|
|
65
|
+
{ scheme: 'utxo', network: BCH_MAINNET_NETWORK, payTo: 'valid1' },
|
|
66
|
+
{ scheme: 'invalid' },
|
|
67
|
+
{ network: BCH_MAINNET_NETWORK, payTo: 'missing-scheme' },
|
|
68
|
+
{ scheme: 'utxo', payTo: 'missing-network' },
|
|
69
|
+
{ scheme: 'utxo', network: BCH_MAINNET_NETWORK },
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
const result = parsePaymentRequiredJson(input);
|
|
73
|
+
expect(result.accepts).toHaveLength(1);
|
|
74
|
+
expect(result.accepts[0].payTo).toBe('valid1');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('selectBchPaymentRequirements', () => {
|
|
78
|
+
const paymentRequired = {
|
|
79
|
+
x402Version: 2,
|
|
80
|
+
resource: { url: 'https://api.example.com' },
|
|
81
|
+
accepts: [
|
|
82
|
+
{
|
|
83
|
+
scheme: 'utxo',
|
|
84
|
+
network: BCH_MAINNET_NETWORK,
|
|
85
|
+
amount: '1000',
|
|
86
|
+
asset: BCH_ASSET_ID,
|
|
87
|
+
payTo: 'bitcoincash:mainnet-address',
|
|
88
|
+
maxTimeoutSeconds: 300,
|
|
89
|
+
extra: {},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
scheme: 'utxo',
|
|
93
|
+
network: BCH_CHIPNET_NETWORK,
|
|
94
|
+
amount: '1000',
|
|
95
|
+
asset: BCH_ASSET_ID,
|
|
96
|
+
payTo: 'bitcoincash:chipnet-address',
|
|
97
|
+
maxTimeoutSeconds: 300,
|
|
98
|
+
extra: {},
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
extensions: {},
|
|
102
|
+
};
|
|
103
|
+
it('should select mainnet requirements for mainnet client', () => {
|
|
104
|
+
const result = selectBchPaymentRequirements(paymentRequired, 'mainnet');
|
|
105
|
+
expect(result).not.toBeNull();
|
|
106
|
+
expect(result.network).toBe(BCH_MAINNET_NETWORK);
|
|
107
|
+
expect(result.payTo).toBe('bitcoincash:mainnet-address');
|
|
108
|
+
});
|
|
109
|
+
it('should select chipnet requirements for chipnet client', () => {
|
|
110
|
+
const result = selectBchPaymentRequirements(paymentRequired, 'chipnet');
|
|
111
|
+
expect(result).not.toBeNull();
|
|
112
|
+
expect(result.network).toBe(BCH_CHIPNET_NETWORK);
|
|
113
|
+
expect(result.payTo).toBe('bitcoincash:chipnet-address');
|
|
114
|
+
});
|
|
115
|
+
it('should return null when no matching network', () => {
|
|
116
|
+
const emptyAccepts = { ...paymentRequired, accepts: [paymentRequired.accepts[0]] };
|
|
117
|
+
const result = selectBchPaymentRequirements(emptyAccepts, 'chipnet');
|
|
118
|
+
expect(result).toBeNull();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
describe('x402 building', () => {
|
|
123
|
+
describe('buildPaymentPayload', () => {
|
|
124
|
+
it('should build a valid PaymentPayload', () => {
|
|
125
|
+
const accepted = {
|
|
126
|
+
scheme: 'utxo',
|
|
127
|
+
network: BCH_MAINNET_NETWORK,
|
|
128
|
+
amount: '1000',
|
|
129
|
+
asset: BCH_ASSET_ID,
|
|
130
|
+
payTo: 'bitcoincash:qp2f5j6q3fj5gjwgk8rkq8xrk8q8q8q8q8q8q8q8',
|
|
131
|
+
maxTimeoutSeconds: 300,
|
|
132
|
+
extra: {},
|
|
133
|
+
};
|
|
134
|
+
const result = buildPaymentPayload(accepted, 'https://api.example.com/data', 'bitcoincash:payer-address', 'abc123txid', 0, '1000');
|
|
135
|
+
expect(result.x402Version).toBe(2);
|
|
136
|
+
expect(result.resource.url).toBe('https://api.example.com/data');
|
|
137
|
+
expect(result.accepted).toBe(accepted);
|
|
138
|
+
expect(result.payload.authorization.from).toBe('bitcoincash:payer-address');
|
|
139
|
+
expect(result.payload.authorization.to).toBe(accepted.payTo);
|
|
140
|
+
expect(result.payload.authorization.txid).toBe('abc123txid');
|
|
141
|
+
expect(result.payload.signature).toBe('');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe('buildAuthorization', () => {
|
|
145
|
+
it('should build a valid Authorization', () => {
|
|
146
|
+
const accepted = {
|
|
147
|
+
scheme: 'utxo',
|
|
148
|
+
network: BCH_MAINNET_NETWORK,
|
|
149
|
+
amount: '1000',
|
|
150
|
+
asset: BCH_ASSET_ID,
|
|
151
|
+
payTo: 'bitcoincash:qp2f5j6q3fj5gjwgk8rkq8xrk8q8q8q8q8q8q8q8',
|
|
152
|
+
maxTimeoutSeconds: 300,
|
|
153
|
+
extra: {},
|
|
154
|
+
};
|
|
155
|
+
const result = buildAuthorization(accepted, 'https://api.example.com/data', 'bitcoincash:payer-address', 'abc123txid', 0, '1000');
|
|
156
|
+
expect(result.from).toBe('bitcoincash:payer-address');
|
|
157
|
+
expect(result.to).toBe(accepted.payTo);
|
|
158
|
+
expect(result.txid).toBe('abc123txid');
|
|
159
|
+
expect(result.vout).toBe(0);
|
|
160
|
+
expect(result.amount).toBe('1000');
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
describe('parsePaymentResponse', () => {
|
|
165
|
+
it('should parse valid isValid response', () => {
|
|
166
|
+
const data = {
|
|
167
|
+
isValid: true,
|
|
168
|
+
payer: 'bitcoincash:abc123',
|
|
169
|
+
remainingBalanceSat: '1000000',
|
|
170
|
+
};
|
|
171
|
+
const result = parsePaymentResponse(data);
|
|
172
|
+
expect(result.isValid).toBe(true);
|
|
173
|
+
expect(result.payer).toBe('bitcoincash:abc123');
|
|
174
|
+
expect(result.remainingBalanceSat).toBe('1000000');
|
|
175
|
+
});
|
|
176
|
+
it('should parse error response', () => {
|
|
177
|
+
const data = { error: 'Invalid signature' };
|
|
178
|
+
const result = parsePaymentResponse(data);
|
|
179
|
+
expect(result.isValid).toBe(false);
|
|
180
|
+
expect(result.invalidReason).toBe('Invalid signature');
|
|
181
|
+
});
|
|
182
|
+
it('should return no_response_data for null input', () => {
|
|
183
|
+
const result = parsePaymentResponse(null);
|
|
184
|
+
expect(result.isValid).toBe(false);
|
|
185
|
+
expect(result.invalidReason).toBe('no_response_data');
|
|
186
|
+
});
|
|
187
|
+
it('should return unknown_response_format for unrecognized data', () => {
|
|
188
|
+
const data = { some: 'unknown', format: true };
|
|
189
|
+
const result = parsePaymentResponse(data);
|
|
190
|
+
expect(result.isValid).toBe(false);
|
|
191
|
+
expect(result.invalidReason).toBe('unknown_response_format');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('network helpers', () => {
|
|
195
|
+
describe('isBchNetwork', () => {
|
|
196
|
+
it('should return true for mainnet', () => {
|
|
197
|
+
expect(isBchNetwork(BCH_MAINNET_NETWORK)).toBe(true);
|
|
198
|
+
});
|
|
199
|
+
it('should return true for chipnet', () => {
|
|
200
|
+
expect(isBchNetwork(BCH_CHIPNET_NETWORK)).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
it('should return false for other networks', () => {
|
|
203
|
+
expect(isBchNetwork('bitcoin')).toBe(false);
|
|
204
|
+
expect(isBchNetwork('litecoin')).toBe(false);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe('isChipnetNetwork', () => {
|
|
208
|
+
it('should return true for chipnet', () => {
|
|
209
|
+
expect(isChipnetNetwork(BCH_CHIPNET_NETWORK)).toBe(true);
|
|
210
|
+
});
|
|
211
|
+
it('should return false for mainnet', () => {
|
|
212
|
+
expect(isChipnetNetwork(BCH_MAINNET_NETWORK)).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
//# sourceMappingURL=x402.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.test.js","sourceRoot":"","sources":["../../src/utils/x402.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 payment handler for BCH
|
|
3
|
+
* Implements x402-bch v2.2 specification
|
|
4
|
+
* https://github.com/x402-bch/x402-bch/blob/master/specs/x402-bch-specification-v2.2.md
|
|
5
|
+
*/
|
|
6
|
+
import { LibauthHDWallet } from './keys.js';
|
|
7
|
+
import { PaymentRequirements, PaymentPayload } from '../types/x402.js';
|
|
8
|
+
export interface X402Signer {
|
|
9
|
+
address: string;
|
|
10
|
+
signMessage: (message: string) => Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
export interface X402PayerConfig {
|
|
13
|
+
hdWallet: LibauthHDWallet;
|
|
14
|
+
addressIndex?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class X402Payer {
|
|
17
|
+
private signer;
|
|
18
|
+
private isChipnet;
|
|
19
|
+
constructor(config: X402PayerConfig);
|
|
20
|
+
private createSigner;
|
|
21
|
+
getPayerAddress(): string;
|
|
22
|
+
createPaymentPayload(requirements: PaymentRequirements, resourceUrl: string, txid: string, vout: number | null, amount: string | null): Promise<PaymentPayload>;
|
|
23
|
+
makePaymentRequest(requirements: PaymentRequirements, resourceUrl: string, txid: string, vout: number | null, amount: string | null): Promise<{
|
|
24
|
+
paymentPayload: PaymentPayload;
|
|
25
|
+
paymentUrl: string;
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
export declare function createX402Payer(hdWallet: LibauthHDWallet, addressIndex?: number): X402Payer;
|
|
29
|
+
//# sourceMappingURL=x402.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../../src/wallet/x402.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAS3C,OAAO,EAEL,mBAAmB,EACnB,cAAc,EAGf,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAClD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,eAAe,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,eAAe;IAKnC,OAAO,CAAC,YAAY;IAYpB,eAAe,IAAI,MAAM;IAInB,oBAAoB,CACxB,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO,CAAC,cAAc,CAAC;IAgBpB,kBAAkB,CACtB,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO,CAAC;QAAE,cAAc,EAAE,cAAc,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAQnE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAE3F"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 payment handler for BCH
|
|
3
|
+
* Implements x402-bch v2.2 specification
|
|
4
|
+
* https://github.com/x402-bch/x402-bch/blob/master/specs/x402-bch-specification-v2.2.md
|
|
5
|
+
*/
|
|
6
|
+
import { buildPaymentPayload, signAuthorization, signMessageBCH, } from '../utils/x402.js';
|
|
7
|
+
export class X402Payer {
|
|
8
|
+
signer;
|
|
9
|
+
isChipnet;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.isChipnet = config.hdWallet.isChipnet;
|
|
12
|
+
this.signer = this.createSigner(config.hdWallet, config.addressIndex || 0);
|
|
13
|
+
}
|
|
14
|
+
createSigner(hdWallet, index) {
|
|
15
|
+
const addressSet = hdWallet.getAddressSetAt(index);
|
|
16
|
+
return {
|
|
17
|
+
address: addressSet.receiving,
|
|
18
|
+
signMessage: async (message) => {
|
|
19
|
+
const node = hdWallet.getNodeAt(`0/${index}`);
|
|
20
|
+
const privKeyHex = Buffer.from(node.privateKey).toString('hex');
|
|
21
|
+
return signMessageBCH(message, privKeyHex, true);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
getPayerAddress() {
|
|
26
|
+
return this.signer.address;
|
|
27
|
+
}
|
|
28
|
+
async createPaymentPayload(requirements, resourceUrl, txid, vout, amount) {
|
|
29
|
+
const payload = buildPaymentPayload(requirements, resourceUrl, this.signer.address, txid, vout, amount);
|
|
30
|
+
const signature = await signAuthorization(payload.payload.authorization, this.signer.signMessage.bind(this.signer));
|
|
31
|
+
payload.payload.signature = signature;
|
|
32
|
+
return payload;
|
|
33
|
+
}
|
|
34
|
+
async makePaymentRequest(requirements, resourceUrl, txid, vout, amount) {
|
|
35
|
+
const paymentPayload = await this.createPaymentPayload(requirements, resourceUrl, txid, vout, amount);
|
|
36
|
+
return {
|
|
37
|
+
paymentPayload,
|
|
38
|
+
paymentUrl: requirements.payTo,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function createX402Payer(hdWallet, addressIndex) {
|
|
43
|
+
return new X402Payer({ hdWallet, addressIndex });
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=x402.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.js","sourceRoot":"","sources":["../../src/wallet/x402.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAGL,mBAAmB,EAEnB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AAmBzB,MAAM,OAAO,SAAS;IACZ,MAAM,CAAY;IAClB,SAAS,CAAS;IAE1B,YAAY,MAAuB;QACjC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAA;QAC1C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC,CAAA;IAC5E,CAAC;IAEO,YAAY,CAAC,QAAyB,EAAE,KAAa;QAC3D,MAAM,UAAU,GAAG,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;QAClD,OAAO;YACL,OAAO,EAAE,UAAU,CAAC,SAAS;YAC7B,WAAW,EAAE,KAAK,EAAE,OAAe,EAAE,EAAE;gBACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,KAAK,EAAE,CAAC,CAAA;gBAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;gBAC/D,OAAO,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,CAAA;YAClD,CAAC;SACF,CAAA;IACH,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,YAAiC,EACjC,WAAmB,EACnB,IAAY,EACZ,IAAmB,EACnB,MAAqB;QAErB,MAAM,OAAO,GAAG,mBAAmB,CACjC,YAAY,EACZ,WAAW,EACX,IAAI,CAAC,MAAM,CAAC,OAAO,EACnB,IAAI,EACJ,IAAI,EACJ,MAAM,CACP,CAAA;QAED,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;QACnH,OAAO,CAAC,OAAO,CAAC,SAAS,GAAG,SAAS,CAAA;QAErC,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,YAAiC,EACjC,WAAmB,EACnB,IAAY,EACZ,IAAmB,EACnB,MAAqB;QAErB,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;QAErG,OAAO;YACL,cAAc;YACd,UAAU,EAAE,YAAY,CAAC,KAAK;SAC/B,CAAA;IACH,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,QAAyB,EAAE,YAAqB;IAC9E,OAAO,IAAI,SAAS,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAA;AAClD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paytaca-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Command-line interface for the Paytaca Bitcoin Cash wallet",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"bin/",
|
|
13
13
|
"dist/",
|
|
14
|
+
"skills/",
|
|
14
15
|
"LICENSE",
|
|
15
16
|
"README.md"
|
|
16
17
|
],
|
|
@@ -19,6 +20,8 @@
|
|
|
19
20
|
"dev": "tsc --watch",
|
|
20
21
|
"start": "node bin/paytaca.js",
|
|
21
22
|
"clean": "rm -rf dist",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
22
25
|
"prepublishOnly": "npm run clean && npm run build"
|
|
23
26
|
},
|
|
24
27
|
"keywords": [
|
|
@@ -49,7 +52,9 @@
|
|
|
49
52
|
"devDependencies": {
|
|
50
53
|
"@types/node": "^22.0.0",
|
|
51
54
|
"@types/qrcode-terminal": "^0.12.2",
|
|
52
|
-
"
|
|
55
|
+
"@vitest/ui": "^4.1.2",
|
|
56
|
+
"typescript": "^5.9.3",
|
|
57
|
+
"vitest": "^4.1.2"
|
|
53
58
|
},
|
|
54
59
|
"engines": {
|
|
55
60
|
"node": ">=20.0.0"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: paytaca-x402
|
|
3
|
+
description: Handles x402 HTTP payment requests using Paytaca BCH wallet. Use when encountering HTTP 402 responses or when calling APIs that may require payment via the x402 protocol.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Paytaca x402 Payment Handler
|
|
7
|
+
|
|
8
|
+
This skill teaches the agent how to handle x402-based HTTP payments using the Paytaca CLI wallet.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Some APIs (like nanogpt, etc.) use the x402 protocol for HTTP payments. When you call these APIs:
|
|
13
|
+
- Server returns **HTTP 402 PAYMENT REQUIRED**
|
|
14
|
+
- You must pay with BCH to access the resource
|
|
15
|
+
- After payment, the server returns the actual response
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
### Check if a URL requires payment (recommended first step)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
paytaca check <url> --json
|
|
23
|
+
# Returns: acceptsX402, acceptsBch, estimatedCostSats, etc.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Example output:
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"url": "https://api.nanogpt.com/v1/complete",
|
|
30
|
+
"acceptsX402": true,
|
|
31
|
+
"acceptsBch": true,
|
|
32
|
+
"paymentRequired": true,
|
|
33
|
+
"estimatedCostSats": "100",
|
|
34
|
+
"costInBch": "0.00000100"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Preview payment without executing (dry-run)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
paytaca pay <url> --dry-run --json
|
|
42
|
+
# Shows what would happen without actually paying
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Make a paid request
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Basic (will prompt for confirmation)
|
|
49
|
+
paytaca pay <url>
|
|
50
|
+
|
|
51
|
+
# With JSON output (preferred for AI agents)
|
|
52
|
+
paytaca pay <url> --json
|
|
53
|
+
|
|
54
|
+
# Skip confirmation prompt (only use after user has already approved via paytaca check)
|
|
55
|
+
paytaca pay <url> --confirmed
|
|
56
|
+
|
|
57
|
+
# POST request
|
|
58
|
+
paytaca pay <url> --method POST --body '{"prompt":"hello"}'
|
|
59
|
+
|
|
60
|
+
# Custom headers
|
|
61
|
+
paytaca pay <url> -H "Authorization: Bearer token123"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Check wallet balance
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
paytaca balance
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Decision Flow
|
|
71
|
+
|
|
72
|
+
When preparing to call an unfamiliar API that might require payment:
|
|
73
|
+
|
|
74
|
+
1. **First check**: `paytaca check <url> --json`
|
|
75
|
+
- If `paymentRequired: false` → proceed normally
|
|
76
|
+
- If `paymentRequired: true` and `acceptsBch: true` → inform user of cost and **seek explicit approval** before paying
|
|
77
|
+
- If `paymentRequired: true` but `acceptsBch: false` → inform user
|
|
78
|
+
|
|
79
|
+
2. **When encountering HTTP 402**:
|
|
80
|
+
- Parse the `PAYMENT-REQUIRED` headers
|
|
81
|
+
- **Seek explicit user approval** before spending any BCH
|
|
82
|
+
- Once approved, use `paytaca pay <url> --json` to handle payment
|
|
83
|
+
- The command handles: parse headers → build BCH tx → broadcast → retry with signature
|
|
84
|
+
|
|
85
|
+
3. **For known paid APIs**:
|
|
86
|
+
- **Always seek user approval first**, then use `paytaca pay <url>` - it handles 402 automatically
|
|
87
|
+
|
|
88
|
+
## ⚠️ User Approval Required Before Any Payment
|
|
89
|
+
|
|
90
|
+
**CRITICAL**: The agent MUST NOT execute `paytaca pay` without explicit user approval. Since `paytaca pay` spends real BCH from the user's wallet, always:
|
|
91
|
+
|
|
92
|
+
1. Run `paytaca check <url> --json` first to determine the cost
|
|
93
|
+
2. Inform the user of the cost (e.g., "This API costs ~1000 sats")
|
|
94
|
+
3. Wait for explicit user confirmation (e.g., "yes", "go ahead", "pay")
|
|
95
|
+
4. Only then execute the payment using `paytaca pay <url> --confirmed --json`
|
|
96
|
+
|
|
97
|
+
The `--confirmed` flag skips the interactive confirmation prompt since the user has already approved the transaction. Do NOT use `--confirmed` without first obtaining explicit user approval.
|
|
98
|
+
|
|
99
|
+
Do NOT assume the user wants to pay - even if the cost seems small.
|
|
100
|
+
|
|
101
|
+
## AI Agent Workflow
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
Task: Call nanogpt API
|
|
105
|
+
Agent: paytaca check https://api.nanogpt.com/v1/complete --json
|
|
106
|
+
→ {"acceptsBch": true, "estimatedCostSats": "100"}
|
|
107
|
+
|
|
108
|
+
Agent: Informs user "This API costs 100 sats (0.00000100 BCH). Approve to proceed?"
|
|
109
|
+
User: "yes"
|
|
110
|
+
|
|
111
|
+
Agent: paytaca pay https://api.nanogpt.com/v1/complete --method POST --body '{"prompt":"hello"}' --confirmed --json
|
|
112
|
+
→ Handles 402 → pays 100 sats → returns response with txid
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Key Options
|
|
116
|
+
|
|
117
|
+
| Option | Description |
|
|
118
|
+
|--------|-------------|
|
|
119
|
+
| `--json` | Machine-readable output (recommended for AI) |
|
|
120
|
+
| `--dry-run` | Preview payment without executing |
|
|
121
|
+
| `--confirmed` | Skip confirmation prompt (prior approval obtained) |
|
|
122
|
+
| `--chipnet` | Use chipnet (testnet) instead of mainnet |
|
|
123
|
+
| `--max-amount` | Override max payment amount in sats |
|
|
124
|
+
|
|
125
|
+
## Notes
|
|
126
|
+
|
|
127
|
+
- Payment is per-request (no batching)
|
|
128
|
+
- Each request = separate BCH transaction
|
|
129
|
+
- Only BCH payments are supported (no stablecoins)
|
|
130
|
+
- Uses local wallet from OS keychain (credentials never leave the machine)
|