openzoo 0.49.16 → 0.49.17

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/lib/xburner.js DELETED
@@ -1,80 +0,0 @@
1
- /**
2
- * A managed x402 burner per X account, DERIVED not stored.
3
- *
4
- * @openzoobot's paid lane needs the ASKER to pay, and an X reply is a terrible
5
- * place to ask someone to install a wallet. So each X account id gets a burner
6
- * the zoo drives on their behalf, funded by them and auto-topped-up, holding
7
- * only a working balance — the same shape as the local burner `npx openzoo`
8
- * already creates, one per account instead of one per machine.
9
- *
10
- * DERIVED, NOT STORED, and that is the whole security argument:
11
- * seed(user) = HMAC-SHA512(master, "openzoo-xbot-v1:" + userId)
12
- * There is exactly ONE secret on disk no matter how many accounts ever mention
13
- * the bot. A per-user keyfile store would mean thousands of secrets, a backup
14
- * problem, a deletion problem, and a breach that scales with adoption. Here the
15
- * blast radius is one file that already had to be protected, and a burner can
16
- * be re-derived on any machine from that file alone — nothing to lose, nothing
17
- * to migrate, no keypair that exists only on whichever laptop ran the poller.
18
- *
19
- * The tradeoff, stated plainly: the master file CAN derive every burner, so it
20
- * is as sensitive as all of them combined. That is why it is 0600, never
21
- * logged, never sent anywhere, and why balances are kept at working size by
22
- * auto top-up rather than being allowed to accumulate.
23
- */
24
-
25
- import fs from 'node:fs';
26
- import os from 'node:os';
27
- import path from 'node:path';
28
- import crypto from 'node:crypto';
29
- import { Keypair } from '@solana/web3.js';
30
-
31
- const MASTER_FILE = process.env.OPENZOO_XBOT_MASTER
32
- || path.join(os.homedir(), '.openzoo', 'xbot-master.key');
33
-
34
- /** Bump if the derivation ever changes — old burners must keep deriving. */
35
- const DERIVATION = 'openzoo-xbot-v1';
36
-
37
- export function loadOrCreateMaster(file = MASTER_FILE) {
38
- try {
39
- const hex = fs.readFileSync(file, 'utf8').trim();
40
- const buf = Buffer.from(hex, 'hex');
41
- if (buf.length === 32) return buf;
42
- throw new Error('bad length');
43
- } catch {
44
- const buf = crypto.randomBytes(32);
45
- fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
46
- // wx: never clobber an existing master. Overwriting it would orphan every
47
- // burner ever handed out — funds still on-chain, key unrecoverable.
48
- try {
49
- fs.writeFileSync(file, buf.toString('hex') + '\n', { mode: 0o600, flag: 'wx' });
50
- } catch {
51
- return Buffer.from(fs.readFileSync(file, 'utf8').trim(), 'hex');
52
- }
53
- return buf;
54
- }
55
- }
56
-
57
- /**
58
- * Deterministic burner for an X user id.
59
- * Keyed on the numeric id, never the handle: handles are reassignable, and a
60
- * burner that follows a renamed handle would hand a new owner the old wallet.
61
- */
62
- export function deriveBurner(xUserId, master = loadOrCreateMaster()) {
63
- if (!xUserId) throw new Error('deriveBurner needs an X user id');
64
- const mac = crypto.createHmac('sha512', master)
65
- .update(`${DERIVATION}:${String(xUserId)}`)
66
- .digest();
67
- const keypair = Keypair.fromSeed(Uint8Array.from(mac.subarray(0, 32)));
68
- const evmPrivateKey = `0x${mac.subarray(32, 64).toString('hex')}`;
69
- return {
70
- keypair,
71
- evmPrivateKey,
72
- address: keypair.publicKey.toBase58(),
73
- xUserId: String(xUserId),
74
- };
75
- }
76
-
77
- /** Address only — for a reply that tells someone where to send funds. */
78
- export function burnerAddress(xUserId, master) {
79
- return deriveBurner(xUserId, master).address;
80
- }