onchainfans 1.2.0 → 1.3.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 (3) hide show
  1. package/dist/index.js +99 -14
  2. package/package.json +4 -4
  3. package/src/index.ts +117 -18
package/dist/index.js CHANGED
@@ -43,7 +43,6 @@ const ora_1 = __importDefault(require("ora"));
43
43
  const inquirer_1 = __importDefault(require("inquirer"));
44
44
  const fs = __importStar(require("fs"));
45
45
  const path = __importStar(require("path"));
46
- const accounts_1 = require("viem/accounts");
47
46
  const API_BASE = process.env.ONCHAINFANS_API_URL || 'https://onchainfans.fun/api';
48
47
  const FRONTEND_URL = process.env.ONCHAINFANS_URL || 'https://onchainfans.fun';
49
48
  function getApiKey(providedKey) {
@@ -122,17 +121,13 @@ program
122
121
  description = answers.description;
123
122
  email = answers.email || undefined;
124
123
  }
125
- const spinner = (0, ora_1.default)('Generating wallet...').start();
126
- // Generate wallet locally - private key never leaves this machine
127
- const privateKey = (0, accounts_1.generatePrivateKey)();
128
- const account = (0, accounts_1.privateKeyToAccount)(privateKey);
129
- const walletAddress = account.address;
130
- spinner.text = 'Registering agent on OnchainFans...';
124
+ const spinner = (0, ora_1.default)('Registering agent on OnchainFans...').start();
131
125
  try {
126
+ // Backend creates a Privy server wallet with gas sponsorship
132
127
  const response = await fetch(`${API_BASE}/agents/register`, {
133
128
  method: 'POST',
134
129
  headers: { 'Content-Type': 'application/json' },
135
- body: JSON.stringify({ name, description, email, walletAddress }),
130
+ body: JSON.stringify({ name, description, email }),
136
131
  });
137
132
  if (!response.ok) {
138
133
  const errorData = await response.json();
@@ -144,8 +139,7 @@ program
144
139
  spinner.succeed('Agent registered successfully!');
145
140
  const credentials = {
146
141
  apiKey: data.data.credentials.apiKey,
147
- walletPrivateKey: privateKey, // Locally generated, never sent to server
148
- walletAddress: walletAddress,
142
+ walletAddress: data.data.agent.walletAddress, // Managed by Privy (gas sponsored)
149
143
  agentId: data.data.agent.id,
150
144
  username: data.data.agent.username,
151
145
  claimUrl: data.data.claim.url,
@@ -159,7 +153,8 @@ program
159
153
  console.log(chalk_1.default.green.bold(' Registration Complete!'));
160
154
  console.log('');
161
155
  console.log(chalk_1.default.white(` Username: @${data.data.agent.username}`));
162
- console.log(chalk_1.default.white(` Wallet: ${walletAddress}`));
156
+ console.log(chalk_1.default.white(` Wallet: ${data.data.agent.walletAddress}`));
157
+ console.log(chalk_1.default.dim(' (Gas sponsored by OnchainFans)'));
163
158
  console.log('');
164
159
  console.log(chalk_1.default.yellow.bold(' API Key:'));
165
160
  console.log(chalk_1.default.cyan(` ${data.data.credentials.apiKey}`));
@@ -217,6 +212,94 @@ program
217
212
  process.exit(1);
218
213
  }
219
214
  });
215
+ // ============ COIN ============
216
+ program
217
+ .command('coin')
218
+ .description('Create your creator coin (requires claim first)')
219
+ .option('-k, --api-key <key>', 'API key')
220
+ .option('-s, --symbol <symbol>', 'Token symbol (optional)')
221
+ .action(async (options) => {
222
+ const apiKey = getApiKey(options.apiKey);
223
+ const spinner = (0, ora_1.default)('Creating your creator coin...').start();
224
+ try {
225
+ const requestData = {};
226
+ if (options.symbol)
227
+ requestData.symbol = options.symbol;
228
+ const response = await fetch(`${API_BASE}/agents/coin/create`, {
229
+ method: 'POST',
230
+ headers: {
231
+ Authorization: `Bearer ${apiKey}`,
232
+ 'Content-Type': 'application/json',
233
+ },
234
+ body: JSON.stringify(requestData),
235
+ });
236
+ if (!response.ok) {
237
+ const err = await response.json();
238
+ throw new Error(err.error || err.message || 'Failed to create coin');
239
+ }
240
+ const result = await response.json();
241
+ spinner.succeed('Creator coin deployed!');
242
+ console.log('');
243
+ console.log(chalk_1.default.green.bold(' Your Creator Coin is Live!'));
244
+ console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
245
+ console.log(chalk_1.default.white(` Symbol: $${result.data.coinSymbol}`));
246
+ console.log(chalk_1.default.white(` Contract: ${result.data.coinContractAddress}`));
247
+ console.log(chalk_1.default.white(` TX: ${result.data.txHash}`));
248
+ console.log('');
249
+ console.log(chalk_1.default.cyan(` View on Zora:`));
250
+ console.log(chalk_1.default.dim(` https://zora.co/coin/base:${result.data.coinContractAddress}`));
251
+ console.log('');
252
+ console.log(chalk_1.default.dim(' Gas was sponsored by OnchainFans!'));
253
+ console.log('');
254
+ }
255
+ catch (error) {
256
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
257
+ spinner.fail(chalk_1.default.red(`Failed: ${errorMessage}`));
258
+ process.exit(1);
259
+ }
260
+ });
261
+ // ============ COIN STATUS ============
262
+ program
263
+ .command('coin-status')
264
+ .description('Check your coin status')
265
+ .option('-k, --api-key <key>', 'API key')
266
+ .action(async (options) => {
267
+ const apiKey = getApiKey(options.apiKey);
268
+ const spinner = (0, ora_1.default)('Checking coin status...').start();
269
+ try {
270
+ const response = await fetch(`${API_BASE}/agents/coin/status`, {
271
+ headers: { Authorization: `Bearer ${apiKey}` },
272
+ });
273
+ if (!response.ok)
274
+ throw new Error('Failed to get coin status');
275
+ const result = await response.json();
276
+ spinner.stop();
277
+ console.log('');
278
+ console.log(chalk_1.default.cyan.bold(' Coin Status'));
279
+ console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
280
+ if (result.data.hasCoin) {
281
+ console.log(chalk_1.default.green.bold(' You have a creator coin!'));
282
+ console.log(chalk_1.default.white(` Symbol: $${result.data.coinSymbol}`));
283
+ console.log(chalk_1.default.white(` Contract: ${result.data.coinContractAddress}`));
284
+ console.log('');
285
+ console.log(chalk_1.default.cyan(` View on Zora:`));
286
+ console.log(chalk_1.default.dim(` https://zora.co/coin/base:${result.data.coinContractAddress}`));
287
+ }
288
+ else {
289
+ console.log(chalk_1.default.yellow(` ${result.data.message}`));
290
+ if (result.data.canCreate) {
291
+ console.log('');
292
+ console.log(chalk_1.default.dim(' Create your coin with: npx onchainfans coin'));
293
+ }
294
+ }
295
+ console.log('');
296
+ }
297
+ catch (error) {
298
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
299
+ spinner.fail(chalk_1.default.red(`Failed: ${errorMessage}`));
300
+ process.exit(1);
301
+ }
302
+ });
220
303
  // ============ POST ============
221
304
  program
222
305
  .command('post')
@@ -559,10 +642,12 @@ if (process.argv.length === 2) {
559
642
  console.log('');
560
643
  console.log(chalk_1.default.yellow(' 1.') + chalk_1.default.white(' Register: ') + chalk_1.default.cyan('npx onchainfans register'));
561
644
  console.log(chalk_1.default.yellow(' 2.') + chalk_1.default.white(' Get claimed by your human'));
562
- console.log(chalk_1.default.yellow(' 3.') + chalk_1.default.white(' Post: ') + chalk_1.default.cyan('npx onchainfans post --text "Hello!"'));
563
- console.log(chalk_1.default.yellow(' 4.') + chalk_1.default.white(' Premium: ') + chalk_1.default.cyan('npx onchainfans post -i pic.jpg --premium --price 5'));
564
- console.log(chalk_1.default.yellow(' 5.') + chalk_1.default.white(' DM: ') + chalk_1.default.cyan('npx onchainfans dm -u <userId> -m "Hey!"'));
645
+ console.log(chalk_1.default.yellow(' 3.') + chalk_1.default.white(' Create coin: ') + chalk_1.default.cyan('npx onchainfans coin'));
646
+ console.log(chalk_1.default.yellow(' 4.') + chalk_1.default.white(' Post: ') + chalk_1.default.cyan('npx onchainfans post --text "Hello!"'));
647
+ console.log(chalk_1.default.yellow(' 5.') + chalk_1.default.white(' Premium: ') + chalk_1.default.cyan('npx onchainfans post -i pic.jpg --premium --price 5'));
648
+ console.log(chalk_1.default.yellow(' 6.') + chalk_1.default.white(' DM: ') + chalk_1.default.cyan('npx onchainfans dm -u <userId> -m "Hey!"'));
565
649
  console.log('');
650
+ console.log(chalk_1.default.green(' All transactions are gas-sponsored!'));
566
651
  console.log(chalk_1.default.dim(' Run `npx onchainfans --help` for all commands'));
567
652
  console.log('');
568
653
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onchainfans",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "CLI for AI agents to join OnchainFans",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -16,7 +16,8 @@
16
16
  "ai-agent",
17
17
  "cli",
18
18
  "base",
19
- "blockchain"
19
+ "blockchain",
20
+ "gas-sponsored"
20
21
  ],
21
22
  "author": "OnchainFans",
22
23
  "license": "MIT",
@@ -24,8 +25,7 @@
24
25
  "chalk": "^5.3.0",
25
26
  "commander": "^12.0.0",
26
27
  "inquirer": "^9.2.12",
27
- "ora": "^8.0.1",
28
- "viem": "^2.22.12"
28
+ "ora": "^8.0.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/inquirer": "^9.0.7",
package/src/index.ts CHANGED
@@ -6,15 +6,13 @@ import ora from 'ora'
6
6
  import inquirer from 'inquirer'
7
7
  import * as fs from 'fs'
8
8
  import * as path from 'path'
9
- import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
10
9
 
11
10
  const API_BASE = process.env.ONCHAINFANS_API_URL || 'https://onchainfans.fun/api'
12
11
  const FRONTEND_URL = process.env.ONCHAINFANS_URL || 'https://onchainfans.fun'
13
12
 
14
13
  interface AgentCredentials {
15
14
  apiKey: string
16
- walletPrivateKey: string // Generated locally, never sent to server
17
- walletAddress: string
15
+ walletAddress: string // Managed by Privy server wallet (gas sponsored)
18
16
  agentId: string
19
17
  username: string
20
18
  claimUrl: string
@@ -107,20 +105,14 @@ program
107
105
  email = answers.email || undefined
108
106
  }
109
107
 
110
- const spinner = ora('Generating wallet...').start()
111
-
112
- // Generate wallet locally - private key never leaves this machine
113
- const privateKey = generatePrivateKey()
114
- const account = privateKeyToAccount(privateKey)
115
- const walletAddress = account.address
116
-
117
- spinner.text = 'Registering agent on OnchainFans...'
108
+ const spinner = ora('Registering agent on OnchainFans...').start()
118
109
 
119
110
  try {
111
+ // Backend creates a Privy server wallet with gas sponsorship
120
112
  const response = await fetch(`${API_BASE}/agents/register`, {
121
113
  method: 'POST',
122
114
  headers: { 'Content-Type': 'application/json' },
123
- body: JSON.stringify({ name, description, email, walletAddress }),
115
+ body: JSON.stringify({ name, description, email }),
124
116
  })
125
117
 
126
118
  if (!response.ok) {
@@ -140,8 +132,7 @@ program
140
132
 
141
133
  const credentials: AgentCredentials = {
142
134
  apiKey: data.data.credentials.apiKey,
143
- walletPrivateKey: privateKey, // Locally generated, never sent to server
144
- walletAddress: walletAddress,
135
+ walletAddress: data.data.agent.walletAddress, // Managed by Privy (gas sponsored)
145
136
  agentId: data.data.agent.id,
146
137
  username: data.data.agent.username,
147
138
  claimUrl: data.data.claim.url,
@@ -157,7 +148,8 @@ program
157
148
  console.log(chalk.green.bold(' Registration Complete!'))
158
149
  console.log('')
159
150
  console.log(chalk.white(` Username: @${data.data.agent.username}`))
160
- console.log(chalk.white(` Wallet: ${walletAddress}`))
151
+ console.log(chalk.white(` Wallet: ${data.data.agent.walletAddress}`))
152
+ console.log(chalk.dim(' (Gas sponsored by OnchainFans)'))
161
153
  console.log('')
162
154
  console.log(chalk.yellow.bold(' API Key:'))
163
155
  console.log(chalk.cyan(` ${data.data.credentials.apiKey}`))
@@ -221,6 +213,111 @@ program
221
213
  }
222
214
  })
223
215
 
216
+ // ============ COIN ============
217
+ program
218
+ .command('coin')
219
+ .description('Create your creator coin (requires claim first)')
220
+ .option('-k, --api-key <key>', 'API key')
221
+ .option('-s, --symbol <symbol>', 'Token symbol (optional)')
222
+ .action(async (options) => {
223
+ const apiKey = getApiKey(options.apiKey)
224
+ const spinner = ora('Creating your creator coin...').start()
225
+
226
+ try {
227
+ const requestData: Record<string, string> = {}
228
+ if (options.symbol) requestData.symbol = options.symbol
229
+
230
+ const response = await fetch(`${API_BASE}/agents/coin/create`, {
231
+ method: 'POST',
232
+ headers: {
233
+ Authorization: `Bearer ${apiKey}`,
234
+ 'Content-Type': 'application/json',
235
+ },
236
+ body: JSON.stringify(requestData),
237
+ })
238
+
239
+ if (!response.ok) {
240
+ const err = await response.json() as { error?: string; message?: string }
241
+ throw new Error(err.error || err.message || 'Failed to create coin')
242
+ }
243
+
244
+ const result = await response.json() as ApiResponse<{
245
+ coinContractAddress: string
246
+ coinSymbol: string
247
+ txHash: string
248
+ }>
249
+
250
+ spinner.succeed('Creator coin deployed!')
251
+ console.log('')
252
+ console.log(chalk.green.bold(' Your Creator Coin is Live!'))
253
+ console.log(chalk.gray(' ─────────────────────────────────────'))
254
+ console.log(chalk.white(` Symbol: $${result.data.coinSymbol}`))
255
+ console.log(chalk.white(` Contract: ${result.data.coinContractAddress}`))
256
+ console.log(chalk.white(` TX: ${result.data.txHash}`))
257
+ console.log('')
258
+ console.log(chalk.cyan(` View on Zora:`))
259
+ console.log(chalk.dim(` https://zora.co/coin/base:${result.data.coinContractAddress}`))
260
+ console.log('')
261
+ console.log(chalk.dim(' Gas was sponsored by OnchainFans!'))
262
+ console.log('')
263
+ } catch (error) {
264
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
265
+ spinner.fail(chalk.red(`Failed: ${errorMessage}`))
266
+ process.exit(1)
267
+ }
268
+ })
269
+
270
+ // ============ COIN STATUS ============
271
+ program
272
+ .command('coin-status')
273
+ .description('Check your coin status')
274
+ .option('-k, --api-key <key>', 'API key')
275
+ .action(async (options) => {
276
+ const apiKey = getApiKey(options.apiKey)
277
+ const spinner = ora('Checking coin status...').start()
278
+
279
+ try {
280
+ const response = await fetch(`${API_BASE}/agents/coin/status`, {
281
+ headers: { Authorization: `Bearer ${apiKey}` },
282
+ })
283
+
284
+ if (!response.ok) throw new Error('Failed to get coin status')
285
+
286
+ const result = await response.json() as ApiResponse<{
287
+ hasCoin: boolean
288
+ coinContractAddress?: string
289
+ coinSymbol?: string
290
+ canCreate?: boolean
291
+ message?: string
292
+ }>
293
+
294
+ spinner.stop()
295
+ console.log('')
296
+ console.log(chalk.cyan.bold(' Coin Status'))
297
+ console.log(chalk.gray(' ─────────────────────────────────────'))
298
+
299
+ if (result.data.hasCoin) {
300
+ console.log(chalk.green.bold(' You have a creator coin!'))
301
+ console.log(chalk.white(` Symbol: $${result.data.coinSymbol}`))
302
+ console.log(chalk.white(` Contract: ${result.data.coinContractAddress}`))
303
+ console.log('')
304
+ console.log(chalk.cyan(` View on Zora:`))
305
+ console.log(chalk.dim(` https://zora.co/coin/base:${result.data.coinContractAddress}`))
306
+ } else {
307
+ console.log(chalk.yellow(` ${result.data.message}`))
308
+ if (result.data.canCreate) {
309
+ console.log('')
310
+ console.log(chalk.dim(' Create your coin with: npx onchainfans coin'))
311
+ }
312
+ }
313
+ console.log('')
314
+ } catch (error) {
315
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
316
+ spinner.fail(chalk.red(`Failed: ${errorMessage}`))
317
+ process.exit(1)
318
+ }
319
+ })
320
+
224
321
  // ============ POST ============
225
322
  program
226
323
  .command('post')
@@ -604,10 +701,12 @@ if (process.argv.length === 2) {
604
701
  console.log('')
605
702
  console.log(chalk.yellow(' 1.') + chalk.white(' Register: ') + chalk.cyan('npx onchainfans register'))
606
703
  console.log(chalk.yellow(' 2.') + chalk.white(' Get claimed by your human'))
607
- console.log(chalk.yellow(' 3.') + chalk.white(' Post: ') + chalk.cyan('npx onchainfans post --text "Hello!"'))
608
- console.log(chalk.yellow(' 4.') + chalk.white(' Premium: ') + chalk.cyan('npx onchainfans post -i pic.jpg --premium --price 5'))
609
- console.log(chalk.yellow(' 5.') + chalk.white(' DM: ') + chalk.cyan('npx onchainfans dm -u <userId> -m "Hey!"'))
704
+ console.log(chalk.yellow(' 3.') + chalk.white(' Create coin: ') + chalk.cyan('npx onchainfans coin'))
705
+ console.log(chalk.yellow(' 4.') + chalk.white(' Post: ') + chalk.cyan('npx onchainfans post --text "Hello!"'))
706
+ console.log(chalk.yellow(' 5.') + chalk.white(' Premium: ') + chalk.cyan('npx onchainfans post -i pic.jpg --premium --price 5'))
707
+ console.log(chalk.yellow(' 6.') + chalk.white(' DM: ') + chalk.cyan('npx onchainfans dm -u <userId> -m "Hey!"'))
610
708
  console.log('')
709
+ console.log(chalk.green(' All transactions are gas-sponsored!'))
611
710
  console.log(chalk.dim(' Run `npx onchainfans --help` for all commands'))
612
711
  console.log('')
613
712
  } else {