@claws.fun/cli 1.0.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/README.md +204 -0
- package/dist/commands/buy.d.ts +6 -0
- package/dist/commands/buy.d.ts.map +1 -0
- package/dist/commands/buy.js +120 -0
- package/dist/commands/buy.js.map +1 -0
- package/dist/commands/claim.d.ts +6 -0
- package/dist/commands/claim.d.ts.map +1 -0
- package/dist/commands/claim.js +141 -0
- package/dist/commands/claim.js.map +1 -0
- package/dist/commands/config.d.ts +6 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +107 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/create.d.ts +6 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +174 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/sell.d.ts +6 -0
- package/dist/commands/sell.d.ts.map +1 -0
- package/dist/commands/sell.js +134 -0
- package/dist/commands/sell.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +138 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +30 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +176 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/contracts.d.ts +15 -0
- package/dist/utils/contracts.d.ts.map +1 -0
- package/dist/utils/contracts.js +90 -0
- package/dist/utils/contracts.js.map +1 -0
- package/package.json +48 -0
- package/src/commands/buy.ts +136 -0
- package/src/commands/claim.ts +152 -0
- package/src/commands/config.ts +77 -0
- package/src/commands/create.ts +217 -0
- package/src/commands/sell.ts +149 -0
- package/src/commands/status.ts +148 -0
- package/src/index.ts +41 -0
- package/src/utils/config.ts +159 -0
- package/src/utils/contracts.ts +92 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claws config - Configure wallet and network settings
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { getConfig, setConfig, getWallet, ADDRESSES, RPC_URLS } from '../utils/config';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
export const configCommand = new Command('config')
|
|
10
|
+
.description('Configure wallet and network settings')
|
|
11
|
+
.option('-n, --network <network>', 'Set network (sepolia, base)')
|
|
12
|
+
.option('-k, --key <privateKey>', 'Set private key')
|
|
13
|
+
.option('-r, --rpc <url>', 'Set custom RPC URL')
|
|
14
|
+
.option('-s, --show', 'Show current configuration')
|
|
15
|
+
.action(async (options) => {
|
|
16
|
+
console.log(chalk.cyan('🦞 claws.fun CLI Configuration\n'));
|
|
17
|
+
|
|
18
|
+
// Show current config
|
|
19
|
+
if (options.show || (!options.network && !options.key && !options.rpc)) {
|
|
20
|
+
const config = getConfig();
|
|
21
|
+
const wallet = getWallet();
|
|
22
|
+
|
|
23
|
+
console.log(chalk.yellow('Current Configuration:'));
|
|
24
|
+
console.log(` Network: ${chalk.green(config.network || 'sepolia')}`);
|
|
25
|
+
console.log(` RPC URL: ${chalk.green(config.rpcUrl || RPC_URLS[config.network || 'sepolia'])}`);
|
|
26
|
+
console.log(` Private Key: ${config.privateKey ? chalk.green('✓ Set') : chalk.red('✗ Not set')}`);
|
|
27
|
+
|
|
28
|
+
if (wallet) {
|
|
29
|
+
console.log(` Wallet: ${chalk.green(wallet.address)}`);
|
|
30
|
+
const balance = await wallet.provider?.getBalance(wallet.address);
|
|
31
|
+
if (balance !== undefined) {
|
|
32
|
+
console.log(` Balance: ${chalk.green(Number(balance) / 1e18)} ETH`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('\n' + chalk.yellow('Contract Addresses:'));
|
|
37
|
+
const addresses = ADDRESSES[config.network || 'sepolia'];
|
|
38
|
+
Object.entries(addresses).forEach(([name, address]) => {
|
|
39
|
+
console.log(` ${name.padEnd(16)} ${chalk.gray(address)}`);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log('\n' + chalk.gray('Use --help for configuration options'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Set network
|
|
47
|
+
if (options.network) {
|
|
48
|
+
if (!['sepolia', 'base'].includes(options.network)) {
|
|
49
|
+
console.log(chalk.red('Invalid network. Choose: sepolia, base'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
setConfig('network', options.network);
|
|
53
|
+
console.log(chalk.green(`✓ Network set to: ${options.network}`));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Set private key
|
|
57
|
+
if (options.key) {
|
|
58
|
+
try {
|
|
59
|
+
// Validate private key format
|
|
60
|
+
const { ethers } = await import('ethers');
|
|
61
|
+
const wallet = new ethers.Wallet(options.key);
|
|
62
|
+
setConfig('privateKey', options.key);
|
|
63
|
+
console.log(chalk.green(`✓ Private key set for wallet: ${wallet.address}`));
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.log(chalk.red('Invalid private key format'));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Set RPC URL
|
|
71
|
+
if (options.rpc) {
|
|
72
|
+
setConfig('rpcUrl', options.rpc);
|
|
73
|
+
console.log(chalk.green(`✓ RPC URL set to: ${options.rpc}`));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(chalk.gray('\nRun `claws config --show` to view configuration'));
|
|
77
|
+
});
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claws create - Create a new immortal agent
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { ethers } from 'ethers';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import { getWallet, hasWallet, getConfig } from '../utils/config';
|
|
11
|
+
import { getFactoryContract } from '../utils/contracts';
|
|
12
|
+
|
|
13
|
+
export const createCommand = new Command('create')
|
|
14
|
+
.description('Create a new immortal AI agent')
|
|
15
|
+
.option('-n, --name <name>', 'Agent name')
|
|
16
|
+
.option('-s, --symbol <symbol>', 'Token symbol')
|
|
17
|
+
.option('-w, --wallet <address>', 'Agent wallet address (defaults to your wallet)')
|
|
18
|
+
.option('-t, --tier <tier>', 'Tier: premium ($6K mcap) or micro ($1K mcap)', 'premium')
|
|
19
|
+
.option('--social <handle>', 'Social media handle')
|
|
20
|
+
.option('--memory <cid>', 'IPFS CID for memory', '')
|
|
21
|
+
.option('--avatar <cid>', 'IPFS CID for avatar', '')
|
|
22
|
+
.option('--initial-buy <eth>', 'ETH amount for initial token purchase', '0')
|
|
23
|
+
.option('-y, --yes', 'Skip confirmation prompts')
|
|
24
|
+
.action(async (options) => {
|
|
25
|
+
console.log(chalk.cyan('\n🦞 Create Immortal Agent\n'));
|
|
26
|
+
|
|
27
|
+
// Check wallet
|
|
28
|
+
if (!hasWallet()) {
|
|
29
|
+
console.log(chalk.red('No wallet configured. Run: claws config --key <privateKey>'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const wallet = getWallet()!;
|
|
34
|
+
const config = getConfig();
|
|
35
|
+
|
|
36
|
+
console.log(chalk.gray(`Network: ${config.network}`));
|
|
37
|
+
console.log(chalk.gray(`Wallet: ${wallet.address}\n`));
|
|
38
|
+
|
|
39
|
+
// Gather inputs
|
|
40
|
+
let name = options.name;
|
|
41
|
+
let symbol = options.symbol;
|
|
42
|
+
let agentWallet = options.wallet || wallet.address;
|
|
43
|
+
let tier = options.tier;
|
|
44
|
+
|
|
45
|
+
// Interactive prompts if not provided
|
|
46
|
+
if (!name || !symbol) {
|
|
47
|
+
const answers = await inquirer.prompt([
|
|
48
|
+
{
|
|
49
|
+
type: 'input',
|
|
50
|
+
name: 'name',
|
|
51
|
+
message: 'Agent name:',
|
|
52
|
+
when: !name,
|
|
53
|
+
validate: (input: string) => input.length > 0 || 'Name is required',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: 'input',
|
|
57
|
+
name: 'symbol',
|
|
58
|
+
message: 'Token symbol:',
|
|
59
|
+
when: !symbol,
|
|
60
|
+
validate: (input: string) => input.length > 0 && input.length <= 6 || 'Symbol must be 1-6 characters',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
type: 'list',
|
|
64
|
+
name: 'tier',
|
|
65
|
+
message: 'Select tier:',
|
|
66
|
+
choices: [
|
|
67
|
+
{ name: 'Premium - $6K mcap (0.011 ETH)', value: 'premium' },
|
|
68
|
+
{ name: 'Micro - $1K mcap (0.0013 ETH)', value: 'micro' },
|
|
69
|
+
],
|
|
70
|
+
when: !options.tier,
|
|
71
|
+
default: 'premium',
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
name = name || answers.name;
|
|
76
|
+
symbol = symbol || answers.symbol;
|
|
77
|
+
tier = tier || answers.tier;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Get costs
|
|
81
|
+
const factory = getFactoryContract(wallet);
|
|
82
|
+
const premiumCost = await factory.PREMIUM_TOTAL();
|
|
83
|
+
const microCost = await factory.MICRO_TOTAL();
|
|
84
|
+
const cost = tier === 'premium' ? premiumCost : microCost;
|
|
85
|
+
const initialBuy = ethers.parseEther(options.initialBuy || '0');
|
|
86
|
+
const totalCost = cost + initialBuy;
|
|
87
|
+
|
|
88
|
+
// Check balance
|
|
89
|
+
const balance = await wallet.provider?.getBalance(wallet.address);
|
|
90
|
+
if (balance && balance < totalCost) {
|
|
91
|
+
console.log(chalk.red(`Insufficient balance. Need ${ethers.formatEther(totalCost)} ETH, have ${ethers.formatEther(balance)} ETH`));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Show summary
|
|
96
|
+
console.log(chalk.yellow('\nAgent Details:'));
|
|
97
|
+
console.log(` Name: ${chalk.white(name)}`);
|
|
98
|
+
console.log(` Symbol: ${chalk.white(symbol)}`);
|
|
99
|
+
console.log(` Wallet: ${chalk.gray(agentWallet)}`);
|
|
100
|
+
console.log(` Tier: ${chalk.green(tier.toUpperCase())}`);
|
|
101
|
+
console.log(` Cost: ${chalk.cyan(ethers.formatEther(cost))} ETH`);
|
|
102
|
+
if (initialBuy > 0n) {
|
|
103
|
+
console.log(` Initial Buy: ${chalk.cyan(ethers.formatEther(initialBuy))} ETH`);
|
|
104
|
+
}
|
|
105
|
+
console.log(` Total: ${chalk.cyan(ethers.formatEther(totalCost))} ETH`);
|
|
106
|
+
|
|
107
|
+
// Confirmation
|
|
108
|
+
if (!options.yes) {
|
|
109
|
+
const { confirm } = await inquirer.prompt([{
|
|
110
|
+
type: 'confirm',
|
|
111
|
+
name: 'confirm',
|
|
112
|
+
message: 'Create agent?',
|
|
113
|
+
default: true,
|
|
114
|
+
}]);
|
|
115
|
+
|
|
116
|
+
if (!confirm) {
|
|
117
|
+
console.log(chalk.yellow('Cancelled'));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Create agent
|
|
123
|
+
const spinner = ora('Creating agent...').start();
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
let tx;
|
|
127
|
+
|
|
128
|
+
if (tier === 'micro') {
|
|
129
|
+
tx = await factory.createMicroAgent(
|
|
130
|
+
agentWallet,
|
|
131
|
+
ethers.ZeroAddress, // self-created
|
|
132
|
+
name,
|
|
133
|
+
symbol,
|
|
134
|
+
options.social || '',
|
|
135
|
+
options.memory || '',
|
|
136
|
+
options.avatar || '',
|
|
137
|
+
'',
|
|
138
|
+
initialBuy,
|
|
139
|
+
{
|
|
140
|
+
value: totalCost,
|
|
141
|
+
gasLimit: 8_000_000,
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
} else {
|
|
145
|
+
if (initialBuy > 0n) {
|
|
146
|
+
tx = await factory['createAgent(address,address,string,string,string,string,string,string,uint256)'](
|
|
147
|
+
agentWallet,
|
|
148
|
+
ethers.ZeroAddress,
|
|
149
|
+
name,
|
|
150
|
+
symbol,
|
|
151
|
+
options.social || '',
|
|
152
|
+
options.memory || '',
|
|
153
|
+
options.avatar || '',
|
|
154
|
+
'',
|
|
155
|
+
initialBuy,
|
|
156
|
+
{
|
|
157
|
+
value: totalCost,
|
|
158
|
+
gasLimit: 8_000_000,
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
} else {
|
|
162
|
+
tx = await factory['createAgent(address,address,string,string,string,string,string,string)'](
|
|
163
|
+
agentWallet,
|
|
164
|
+
ethers.ZeroAddress,
|
|
165
|
+
name,
|
|
166
|
+
symbol,
|
|
167
|
+
options.social || '',
|
|
168
|
+
options.memory || '',
|
|
169
|
+
options.avatar || '',
|
|
170
|
+
'',
|
|
171
|
+
{
|
|
172
|
+
value: totalCost,
|
|
173
|
+
gasLimit: 8_000_000,
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
spinner.text = 'Waiting for confirmation...';
|
|
180
|
+
const receipt = await tx.wait();
|
|
181
|
+
|
|
182
|
+
// Parse events to get token address
|
|
183
|
+
const factoryInterface = factory.interface;
|
|
184
|
+
let tokenAddress = '';
|
|
185
|
+
let poolAddress = '';
|
|
186
|
+
let nftId = '';
|
|
187
|
+
|
|
188
|
+
for (const log of receipt.logs) {
|
|
189
|
+
try {
|
|
190
|
+
const parsed = factoryInterface.parseLog(log);
|
|
191
|
+
if (parsed && parsed.name === 'AgentBorn') {
|
|
192
|
+
tokenAddress = parsed.args.token;
|
|
193
|
+
poolAddress = parsed.args.pool;
|
|
194
|
+
nftId = parsed.args.nftId.toString();
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
} catch (e) {
|
|
198
|
+
// Skip non-factory events
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
spinner.succeed(chalk.green('Agent created successfully!'));
|
|
203
|
+
|
|
204
|
+
console.log('\n' + chalk.yellow('Agent Details:'));
|
|
205
|
+
console.log(` Token: ${chalk.green(tokenAddress)}`);
|
|
206
|
+
console.log(` Pool: ${chalk.gray(poolAddress)}`);
|
|
207
|
+
console.log(` NFT ID: ${chalk.cyan(nftId)}`);
|
|
208
|
+
console.log(` TX Hash: ${chalk.gray(receipt.hash)}`);
|
|
209
|
+
console.log(` Gas Used: ${chalk.gray(receipt.gasUsed.toString())}`);
|
|
210
|
+
|
|
211
|
+
console.log('\n' + chalk.cyan(`🔗 View your agent: https://claws.fun/agent/${tokenAddress}`));
|
|
212
|
+
|
|
213
|
+
} catch (error: any) {
|
|
214
|
+
spinner.fail(chalk.red('Failed to create agent'));
|
|
215
|
+
console.log(chalk.red(`Error: ${error.message || error}`));
|
|
216
|
+
}
|
|
217
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claws sell - Sell agent tokens
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { ethers } from 'ethers';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import { getWallet, hasWallet, getConfig, getNetworkAddresses } from '../utils/config';
|
|
11
|
+
import { getTokenContract, getSwapRouterContract, getWethContract } from '../utils/contracts';
|
|
12
|
+
|
|
13
|
+
export const sellCommand = new Command('sell')
|
|
14
|
+
.description('Sell agent tokens')
|
|
15
|
+
.argument('<token>', 'Token address to sell')
|
|
16
|
+
.option('-a, --amount <tokens>', 'Token amount to sell (or "all")')
|
|
17
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
18
|
+
.action(async (tokenAddress, options) => {
|
|
19
|
+
console.log(chalk.cyan('\n🦞 Sell Agent Tokens\n'));
|
|
20
|
+
|
|
21
|
+
if (!hasWallet()) {
|
|
22
|
+
console.log(chalk.red('No wallet configured. Run: claws config --key <privateKey>'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const wallet = getWallet()!;
|
|
27
|
+
const config = getConfig();
|
|
28
|
+
const addresses = getNetworkAddresses();
|
|
29
|
+
|
|
30
|
+
console.log(chalk.gray(`Network: ${config.network}`));
|
|
31
|
+
console.log(chalk.gray(`Wallet: ${wallet.address}\n`));
|
|
32
|
+
|
|
33
|
+
// Get token info
|
|
34
|
+
const token = getTokenContract(tokenAddress, wallet);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const name = await token.name();
|
|
38
|
+
const symbol = await token.symbol();
|
|
39
|
+
const balance = await token.balanceOf(wallet.address);
|
|
40
|
+
const taxBps = await token.getCurrentTaxBps();
|
|
41
|
+
|
|
42
|
+
console.log(chalk.yellow('Token Info:'));
|
|
43
|
+
console.log(` Name: ${chalk.white(name)}`);
|
|
44
|
+
console.log(` Symbol: ${chalk.white(symbol)}`);
|
|
45
|
+
console.log(` Balance: ${chalk.green(ethers.formatEther(balance))} ${symbol}`);
|
|
46
|
+
console.log(` Tax: ${chalk.red(Number(taxBps) / 100 + '%')}`);
|
|
47
|
+
|
|
48
|
+
if (balance === 0n) {
|
|
49
|
+
console.log(chalk.yellow('\nNo tokens to sell'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get amount
|
|
54
|
+
let amountTokens = options.amount;
|
|
55
|
+
let sellAmount: bigint;
|
|
56
|
+
|
|
57
|
+
if (!amountTokens) {
|
|
58
|
+
const { amount } = await inquirer.prompt([{
|
|
59
|
+
type: 'input',
|
|
60
|
+
name: 'amount',
|
|
61
|
+
message: `Token amount to sell (max ${ethers.formatEther(balance)} or "all"):`,
|
|
62
|
+
default: 'all',
|
|
63
|
+
validate: (input: string) => {
|
|
64
|
+
if (input.toLowerCase() === 'all') return true;
|
|
65
|
+
const num = parseFloat(input);
|
|
66
|
+
return num > 0 || 'Must be greater than 0';
|
|
67
|
+
},
|
|
68
|
+
}]);
|
|
69
|
+
amountTokens = amount;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (amountTokens.toLowerCase() === 'all') {
|
|
73
|
+
sellAmount = balance;
|
|
74
|
+
} else {
|
|
75
|
+
sellAmount = ethers.parseEther(amountTokens);
|
|
76
|
+
if (sellAmount > balance) {
|
|
77
|
+
console.log(chalk.red('Insufficient token balance'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Calculate expected output
|
|
83
|
+
const taxDeduction = Number(taxBps) / 10000;
|
|
84
|
+
console.log(`\n Selling: ${chalk.cyan(ethers.formatEther(sellAmount))} ${symbol}`);
|
|
85
|
+
console.log(` Tax: ${chalk.red(Number(taxBps)/100 + '%')} will be deducted`);
|
|
86
|
+
|
|
87
|
+
// Confirmation
|
|
88
|
+
if (!options.yes) {
|
|
89
|
+
const { confirm } = await inquirer.prompt([{
|
|
90
|
+
type: 'confirm',
|
|
91
|
+
name: 'confirm',
|
|
92
|
+
message: 'Proceed with sale?',
|
|
93
|
+
default: true,
|
|
94
|
+
}]);
|
|
95
|
+
|
|
96
|
+
if (!confirm) {
|
|
97
|
+
console.log(chalk.yellow('Cancelled'));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Execute swap
|
|
103
|
+
const spinner = ora('Executing swap...').start();
|
|
104
|
+
|
|
105
|
+
const swapRouter = getSwapRouterContract(wallet);
|
|
106
|
+
const weth = getWethContract(wallet);
|
|
107
|
+
|
|
108
|
+
// Approve router
|
|
109
|
+
spinner.text = 'Approving router...';
|
|
110
|
+
const approveTx = await token.approve(addresses.swapRouter, sellAmount);
|
|
111
|
+
await approveTx.wait();
|
|
112
|
+
|
|
113
|
+
// Swap tokens for WETH
|
|
114
|
+
spinner.text = 'Swapping tokens for WETH...';
|
|
115
|
+
const swapParams = {
|
|
116
|
+
tokenIn: tokenAddress,
|
|
117
|
+
tokenOut: addresses.weth,
|
|
118
|
+
fee: 10000, // 1% fee tier
|
|
119
|
+
recipient: wallet.address,
|
|
120
|
+
amountIn: sellAmount,
|
|
121
|
+
amountOutMinimum: 0, // No slippage protection for simplicity
|
|
122
|
+
sqrtPriceLimitX96: 0,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const swapTx = await swapRouter.exactInputSingle(swapParams);
|
|
126
|
+
await swapTx.wait();
|
|
127
|
+
|
|
128
|
+
// Unwrap WETH
|
|
129
|
+
spinner.text = 'Unwrapping WETH...';
|
|
130
|
+
const wethBalance = await weth.balanceOf(wallet.address);
|
|
131
|
+
if (wethBalance > 0n) {
|
|
132
|
+
const unwrapTx = await weth.withdraw(wethBalance);
|
|
133
|
+
await unwrapTx.wait();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Get new balances
|
|
137
|
+
const newTokenBalance = await token.balanceOf(wallet.address);
|
|
138
|
+
const ethBalance = await wallet.provider?.getBalance(wallet.address);
|
|
139
|
+
|
|
140
|
+
spinner.succeed(chalk.green('Sale complete!'));
|
|
141
|
+
|
|
142
|
+
console.log('\n' + chalk.yellow('Result:'));
|
|
143
|
+
console.log(` Remaining tokens: ${chalk.cyan(ethers.formatEther(newTokenBalance))} ${symbol}`);
|
|
144
|
+
console.log(` ETH balance: ${chalk.green(ethers.formatEther(ethBalance || 0n))} ETH`);
|
|
145
|
+
|
|
146
|
+
} catch (error: any) {
|
|
147
|
+
console.log(chalk.red(`Error: ${error.message || error}`));
|
|
148
|
+
}
|
|
149
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claws status - Check agent status
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { ethers } from 'ethers';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { getWallet, getProvider, getConfig } from '../utils/config';
|
|
9
|
+
import { getTokenContract, getFeeCollectorContract, getFactoryContract } from '../utils/contracts';
|
|
10
|
+
|
|
11
|
+
export const statusCommand = new Command('status')
|
|
12
|
+
.description('Check agent status')
|
|
13
|
+
.argument('[token]', 'Token address (or wallet address)')
|
|
14
|
+
.action(async (address) => {
|
|
15
|
+
console.log(chalk.cyan('\n🦞 Agent Status\n'));
|
|
16
|
+
|
|
17
|
+
const config = getConfig();
|
|
18
|
+
const provider = getProvider();
|
|
19
|
+
const wallet = getWallet();
|
|
20
|
+
|
|
21
|
+
console.log(chalk.gray(`Network: ${config.network}`));
|
|
22
|
+
if (wallet) {
|
|
23
|
+
console.log(chalk.gray(`Your wallet: ${wallet.address}`));
|
|
24
|
+
}
|
|
25
|
+
console.log('');
|
|
26
|
+
|
|
27
|
+
// If no address, show user's agent if wallet configured
|
|
28
|
+
if (!address && wallet) {
|
|
29
|
+
const factory = getFactoryContract();
|
|
30
|
+
const tokenAddress = await factory.tokenByWallet(wallet.address);
|
|
31
|
+
|
|
32
|
+
if (tokenAddress && tokenAddress !== ethers.ZeroAddress) {
|
|
33
|
+
address = tokenAddress;
|
|
34
|
+
console.log(chalk.gray(`Found your agent: ${address}\n`));
|
|
35
|
+
} else {
|
|
36
|
+
console.log(chalk.yellow('No address provided and no agent found for your wallet'));
|
|
37
|
+
console.log(chalk.gray('Usage: claws status <token-address>'));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!address) {
|
|
43
|
+
console.log(chalk.red('Please provide a token or wallet address'));
|
|
44
|
+
console.log(chalk.gray('Usage: claws status <address>'));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check if it's a wallet address (has an agent)
|
|
49
|
+
const factory = getFactoryContract();
|
|
50
|
+
let tokenAddress = address;
|
|
51
|
+
|
|
52
|
+
const isAgent = await factory.isAgent(address);
|
|
53
|
+
if (isAgent) {
|
|
54
|
+
tokenAddress = await factory.tokenByWallet(address);
|
|
55
|
+
console.log(chalk.gray(`Wallet ${address} has agent token: ${tokenAddress}\n`));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Get token info
|
|
59
|
+
const token = getTokenContract(tokenAddress);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const name = await token.name();
|
|
63
|
+
const symbol = await token.symbol();
|
|
64
|
+
const totalSupply = await token.totalSupply();
|
|
65
|
+
const agentWallet = await token.agentWallet();
|
|
66
|
+
const creator = await token.creator();
|
|
67
|
+
const birthTimestamp = await token.birthTimestamp();
|
|
68
|
+
const selfCreated = await token.selfCreated();
|
|
69
|
+
const launchBlock = await token.launchBlock();
|
|
70
|
+
const pool = await token.pool();
|
|
71
|
+
const taxBps = await token.getCurrentTaxBps();
|
|
72
|
+
|
|
73
|
+
// Get fee info
|
|
74
|
+
const feeCollector = getFeeCollectorContract();
|
|
75
|
+
const [agentPercent, creatorPercent, platformPercent, splitType] = await feeCollector.getFeeSplits(tokenAddress);
|
|
76
|
+
const totalCollected = await feeCollector.getTotalCollected(tokenAddress);
|
|
77
|
+
const pendingTax = await feeCollector.getPendingTokenTax(tokenAddress);
|
|
78
|
+
const positionId = await feeCollector.getPositionId(tokenAddress);
|
|
79
|
+
|
|
80
|
+
// Get current block for tax info
|
|
81
|
+
const currentBlock = await provider.getBlockNumber();
|
|
82
|
+
const blocksSinceLaunch = currentBlock - Number(launchBlock);
|
|
83
|
+
|
|
84
|
+
// Get agent tier
|
|
85
|
+
const tier = await factory.agentTier(tokenAddress);
|
|
86
|
+
const tierName = tier === 0 ? 'PREMIUM' : 'MICRO';
|
|
87
|
+
|
|
88
|
+
// Format birth date
|
|
89
|
+
const birthDate = new Date(Number(birthTimestamp) * 1000).toISOString();
|
|
90
|
+
|
|
91
|
+
console.log(chalk.yellow('═'.repeat(50)));
|
|
92
|
+
console.log(chalk.yellow.bold(` ${name} (${symbol})`));
|
|
93
|
+
console.log(chalk.yellow('═'.repeat(50)));
|
|
94
|
+
|
|
95
|
+
console.log('\n' + chalk.cyan('🤖 Identity'));
|
|
96
|
+
console.log(` Token: ${chalk.green(tokenAddress)}`);
|
|
97
|
+
console.log(` Wallet: ${chalk.gray(agentWallet)}`);
|
|
98
|
+
console.log(` Creator: ${chalk.gray(creator)}`);
|
|
99
|
+
console.log(` Type: ${selfCreated ? chalk.green('Self-Created') : chalk.cyan('Human-Created')}`);
|
|
100
|
+
console.log(` Tier: ${chalk.magenta(tierName)}`);
|
|
101
|
+
console.log(` Born: ${chalk.gray(birthDate)}`);
|
|
102
|
+
|
|
103
|
+
console.log('\n' + chalk.cyan('📊 Token'));
|
|
104
|
+
console.log(` Supply: ${chalk.white(ethers.formatEther(totalSupply))}`);
|
|
105
|
+
console.log(` Pool: ${chalk.gray(pool)}`);
|
|
106
|
+
console.log(` LP NFT: #${chalk.cyan(positionId.toString())}`);
|
|
107
|
+
|
|
108
|
+
console.log('\n' + chalk.cyan('💸 Tax'));
|
|
109
|
+
console.log(` Current: ${chalk.red(Number(taxBps) / 100 + '%')}`);
|
|
110
|
+
console.log(` Launch: Block ${chalk.gray(launchBlock.toString())}`);
|
|
111
|
+
console.log(` Blocks ago: ${chalk.gray(blocksSinceLaunch.toString())}`);
|
|
112
|
+
|
|
113
|
+
// Show tax schedule position
|
|
114
|
+
let taxPhase = '';
|
|
115
|
+
if (blocksSinceLaunch <= 20) taxPhase = '20% (blocks 1-20)';
|
|
116
|
+
else if (blocksSinceLaunch <= 30) taxPhase = '15% (blocks 21-30)';
|
|
117
|
+
else if (blocksSinceLaunch <= 40) taxPhase = '10% (blocks 31-40)';
|
|
118
|
+
else if (blocksSinceLaunch <= 50) taxPhase = '5% (blocks 41-50)';
|
|
119
|
+
else taxPhase = '1% (final rate)';
|
|
120
|
+
console.log(` Phase: ${chalk.yellow(taxPhase)}`);
|
|
121
|
+
|
|
122
|
+
console.log('\n' + chalk.cyan('💰 Fees'));
|
|
123
|
+
console.log(` Split Type: ${chalk.green(splitType)}`);
|
|
124
|
+
console.log(` Agent: ${chalk.green(agentPercent.toString() + '%')}`);
|
|
125
|
+
if (Number(creatorPercent) > 0) {
|
|
126
|
+
console.log(` Creator: ${chalk.cyan(creatorPercent.toString() + '%')}`);
|
|
127
|
+
}
|
|
128
|
+
console.log(` Platform: ${chalk.gray(platformPercent.toString() + '%')}`);
|
|
129
|
+
console.log(` Collected: ${chalk.cyan(ethers.formatEther(totalCollected))} ETH`);
|
|
130
|
+
console.log(` Pending Tax: ${chalk.yellow(ethers.formatEther(pendingTax))} tokens`);
|
|
131
|
+
|
|
132
|
+
// Check wallet balance if configured
|
|
133
|
+
if (wallet) {
|
|
134
|
+
const walletBalance = await token.balanceOf(wallet.address);
|
|
135
|
+
if (walletBalance > 0n) {
|
|
136
|
+
console.log('\n' + chalk.cyan('👛 Your Holdings'));
|
|
137
|
+
console.log(` Balance: ${chalk.green(ethers.formatEther(walletBalance))} ${symbol}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log('\n' + chalk.gray(`🔗 https://claws.fun/agent/${tokenAddress}`));
|
|
142
|
+
console.log('');
|
|
143
|
+
|
|
144
|
+
} catch (error: any) {
|
|
145
|
+
console.log(chalk.red(`Error: ${error.message || error}`));
|
|
146
|
+
console.log(chalk.gray('Make sure the address is a valid agent token or wallet'));
|
|
147
|
+
}
|
|
148
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* claws.fun CLI
|
|
5
|
+
*
|
|
6
|
+
* Command-line interface for AI agents to interact with claws.fun
|
|
7
|
+
*
|
|
8
|
+
* Commands:
|
|
9
|
+
* claws create - Create a new immortal agent
|
|
10
|
+
* claws buy - Buy agent tokens
|
|
11
|
+
* claws sell - Sell agent tokens
|
|
12
|
+
* claws claim - Claim accumulated fees
|
|
13
|
+
* claws status - Check agent status
|
|
14
|
+
* claws config - Configure wallet and network
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Command } from 'commander';
|
|
18
|
+
import { createCommand } from './commands/create';
|
|
19
|
+
import { buyCommand } from './commands/buy';
|
|
20
|
+
import { sellCommand } from './commands/sell';
|
|
21
|
+
import { claimCommand } from './commands/claim';
|
|
22
|
+
import { statusCommand } from './commands/status';
|
|
23
|
+
import { configCommand } from './commands/config';
|
|
24
|
+
|
|
25
|
+
const program = new Command();
|
|
26
|
+
|
|
27
|
+
program
|
|
28
|
+
.name('claws')
|
|
29
|
+
.description('🦞 CLI for AI agents to interact with claws.fun')
|
|
30
|
+
.version('1.0.0');
|
|
31
|
+
|
|
32
|
+
// Register commands
|
|
33
|
+
program.addCommand(createCommand);
|
|
34
|
+
program.addCommand(buyCommand);
|
|
35
|
+
program.addCommand(sellCommand);
|
|
36
|
+
program.addCommand(claimCommand);
|
|
37
|
+
program.addCommand(statusCommand);
|
|
38
|
+
program.addCommand(configCommand);
|
|
39
|
+
|
|
40
|
+
// Parse arguments
|
|
41
|
+
program.parse();
|