naracli 0.1.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.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Config commands
3
+ */
4
+
5
+ import { Command } from "commander";
6
+ import { NaraSDK } from "../../client";
7
+ import { createConfig } from "../../config";
8
+ import { loadWallet, getRpcUrl } from "../utils/wallet";
9
+ import { validatePublicKey } from "../utils/validation";
10
+ import {
11
+ handleTransaction,
12
+ printTransactionResult,
13
+ } from "../utils/transaction";
14
+ import { formatOutput, printError, printInfo } from "../utils/output";
15
+ import type { ConfigCreateOptions } from "../types";
16
+
17
+ /**
18
+ * Register config commands
19
+ * @param program Commander program
20
+ */
21
+ export function registerConfigCommands(program: Command): void {
22
+ const config = program
23
+ .command("config")
24
+ .description("Configuration management commands");
25
+
26
+ // config create
27
+ config
28
+ .command("create")
29
+ .description("Create a bonding curve configuration")
30
+ .option("--fee-claimer <address>", "Fee claimer wallet address")
31
+ .option(
32
+ "--leftover-receiver <address>",
33
+ "Leftover token receiver wallet address"
34
+ )
35
+ .option(
36
+ "--total-supply <number>",
37
+ "Total token supply",
38
+ "1000000000"
39
+ )
40
+ .option("--initial-mcap <number>", "Initial market cap", "30")
41
+ .option("--migration-mcap <number>", "Migration market cap", "540")
42
+ .option("-e, --export-tx", "Export unsigned transaction", false)
43
+ .action(async (options: ConfigCreateOptions) => {
44
+ try {
45
+ await handleConfigCreate(options);
46
+ } catch (error: any) {
47
+ printError(error.message);
48
+ process.exit(1);
49
+ }
50
+ });
51
+ }
52
+
53
+ /**
54
+ * Handle config create command
55
+ * @param options Command options
56
+ */
57
+ async function handleConfigCreate(
58
+ options: ConfigCreateOptions
59
+ ): Promise<void> {
60
+ // Load wallet
61
+ const wallet = await loadWallet(options.wallet);
62
+ const rpcUrl = getRpcUrl(options.rpcUrl);
63
+
64
+ printInfo(`Using RPC: ${rpcUrl}`);
65
+ printInfo(`Wallet: ${wallet.publicKey.toBase58()}`);
66
+
67
+ // Initialize SDK
68
+ const sdk = new NaraSDK({
69
+ rpcUrl,
70
+ commitment: "confirmed",
71
+ });
72
+
73
+ // Parse addresses
74
+ const feeClaimer = options.feeClaimer
75
+ ? validatePublicKey(options.feeClaimer)
76
+ : wallet.publicKey;
77
+ const leftoverReceiver = options.leftoverReceiver
78
+ ? validatePublicKey(options.leftoverReceiver)
79
+ : wallet.publicKey;
80
+
81
+ // Parse numeric options
82
+ const totalTokenSupply = parseInt(String(options.totalSupply || "1000000000"));
83
+ const initialMarketCap = parseFloat(String(options.initialMcap || "30"));
84
+ const migrationMarketCap = parseFloat(String(options.migrationMcap || "540"));
85
+
86
+ printInfo("Creating bonding curve configuration...");
87
+
88
+ // Create config
89
+ const result = await createConfig(sdk, {
90
+ feeClaimer,
91
+ leftoverReceiver,
92
+ payer: wallet.publicKey,
93
+ totalTokenSupply,
94
+ initialMarketCap,
95
+ migrationMarketCap,
96
+ });
97
+
98
+ printInfo(`Config address: ${result.configAddress}`);
99
+
100
+ // Handle transaction
101
+ const txResult = await handleTransaction(
102
+ sdk,
103
+ result.transaction,
104
+ [wallet, result.configKeypair], // Both wallet and config keypair need to sign
105
+ options.exportTx || false
106
+ );
107
+
108
+ // Output result
109
+ if (options.json) {
110
+ const output = {
111
+ configAddress: result.configAddress,
112
+ ...(txResult.signature && { signature: txResult.signature }),
113
+ ...(txResult.base64 && { transaction: txResult.base64 }),
114
+ };
115
+ console.log(JSON.stringify(output, null, 2));
116
+ } else {
117
+ console.log(`\nConfig Address: ${result.configAddress}`);
118
+ printTransactionResult(txResult, false);
119
+
120
+ if (txResult.signature) {
121
+ printInfo("\nSave this DBC config address for creating pools:");
122
+ console.log(`export DBC_CONFIG_ADDRESS="${result.configAddress}"`);
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Migration commands
3
+ */
4
+
5
+ import { Command } from "commander";
6
+ import { NaraSDK } from "../../client";
7
+ import { migrateToDAMMV2, createLocker, canMigrate } from "../../migrate";
8
+ import { loadWallet, getRpcUrl } from "../utils/wallet";
9
+ import { validatePublicKey } from "../utils/validation";
10
+ import {
11
+ handleTransaction,
12
+ printTransactionResult,
13
+ } from "../utils/transaction";
14
+ import { formatOutput, printError, printInfo, printSuccess, printWarning } from "../utils/output";
15
+ import type {
16
+ MigrateLaunchOptions,
17
+ MigrateCreateLockerOptions,
18
+ MigrateCheckOptions,
19
+ } from "../types";
20
+
21
+ /**
22
+ * Register migration commands
23
+ * @param program Commander program
24
+ */
25
+ export function registerMigrateCommands(program: Command): void {
26
+ const migrate = program
27
+ .command("migrate")
28
+ .description("Pool migration commands");
29
+
30
+ // migrate launch
31
+ migrate
32
+ .command("launch <token-address>")
33
+ .description("Migrate pool to DAMM V2 (graduation)")
34
+ .option("-e, --export-tx", "Export unsigned transaction", false)
35
+ .action(
36
+ async (
37
+ tokenAddress: string,
38
+ options: Omit<MigrateLaunchOptions, "tokenAddress">
39
+ ) => {
40
+ try {
41
+ await handleMigrateLaunch(tokenAddress, options);
42
+ } catch (error: any) {
43
+ printError(error.message);
44
+ process.exit(1);
45
+ }
46
+ }
47
+ );
48
+
49
+ // migrate create-locker
50
+ migrate
51
+ .command("create-locker <token-address>")
52
+ .description("Create locker for pools with vesting")
53
+ .option("-e, --export-tx", "Export unsigned transaction", false)
54
+ .action(
55
+ async (
56
+ tokenAddress: string,
57
+ options: Omit<MigrateCreateLockerOptions, "tokenAddress">
58
+ ) => {
59
+ try {
60
+ await handleMigrateCreateLocker(tokenAddress, options);
61
+ } catch (error: any) {
62
+ printError(error.message);
63
+ process.exit(1);
64
+ }
65
+ }
66
+ );
67
+
68
+ // migrate check
69
+ migrate
70
+ .command("check <token-address>")
71
+ .description("Check if pool can be migrated")
72
+ .action(
73
+ async (
74
+ tokenAddress: string,
75
+ options: Omit<MigrateCheckOptions, "tokenAddress">
76
+ ) => {
77
+ try {
78
+ await handleMigrateCheck(tokenAddress, options);
79
+ } catch (error: any) {
80
+ printError(error.message);
81
+ process.exit(1);
82
+ }
83
+ }
84
+ );
85
+ }
86
+
87
+ /**
88
+ * Handle migrate launch command
89
+ * @param tokenAddress Token address
90
+ * @param options Command options
91
+ */
92
+ async function handleMigrateLaunch(
93
+ tokenAddress: string,
94
+ options: Omit<MigrateLaunchOptions, "tokenAddress">
95
+ ): Promise<void> {
96
+ // Load wallet
97
+ const wallet = await loadWallet(options.wallet);
98
+ const rpcUrl = getRpcUrl(options.rpcUrl);
99
+
100
+ printInfo(`Using RPC: ${rpcUrl}`);
101
+ printInfo(`Wallet: ${wallet.publicKey.toBase58()}`);
102
+
103
+ // Validate address
104
+ validatePublicKey(tokenAddress);
105
+
106
+ // Initialize SDK
107
+ const sdk = new NaraSDK({
108
+ rpcUrl,
109
+ commitment: "confirmed",
110
+ });
111
+
112
+ // Check if migration is possible
113
+ printInfo("Checking if pool can be migrated...");
114
+ const checkResult = await canMigrate(sdk, tokenAddress);
115
+
116
+ if (!checkResult.canMigrate) {
117
+ printError(`Cannot migrate: ${checkResult.reason}`);
118
+ process.exit(1);
119
+ }
120
+
121
+ printSuccess("Pool is ready for migration!");
122
+ printInfo("Migrating pool to DAMM V2...");
123
+
124
+ // Migrate to DAMM V2
125
+ const result = await migrateToDAMMV2(sdk, {
126
+ tokenAddress,
127
+ payer: wallet.publicKey,
128
+ });
129
+
130
+ printInfo(`Pool address: ${result.poolAddress}`);
131
+
132
+ // Handle transaction
133
+ // Migration requires three signatures: wallet, firstPositionNftKeypair, secondPositionNftKeypair
134
+ const txResult = await handleTransaction(
135
+ sdk,
136
+ result.transaction,
137
+ [wallet, result.firstPositionNftKeypair, result.secondPositionNftKeypair],
138
+ options.exportTx || false
139
+ );
140
+
141
+ // Output result
142
+ if (options.json) {
143
+ const output = {
144
+ poolAddress: result.poolAddress,
145
+ ...(txResult.signature && { signature: txResult.signature }),
146
+ ...(txResult.base64 && { transaction: txResult.base64 }),
147
+ };
148
+ console.log(JSON.stringify(output, null, 2));
149
+ } else {
150
+ console.log(`\nPool Address: ${result.poolAddress}`);
151
+ printTransactionResult(txResult, false);
152
+
153
+ if (txResult.signature) {
154
+ printSuccess("\nPool successfully migrated to DAMM V2!");
155
+ printInfo("Pool is now a constant product AMM with full liquidity.");
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Handle migrate create-locker command
162
+ * @param tokenAddress Token address
163
+ * @param options Command options
164
+ */
165
+ async function handleMigrateCreateLocker(
166
+ tokenAddress: string,
167
+ options: Omit<MigrateCreateLockerOptions, "tokenAddress">
168
+ ): Promise<void> {
169
+ // Load wallet
170
+ const wallet = await loadWallet(options.wallet);
171
+ const rpcUrl = getRpcUrl(options.rpcUrl);
172
+
173
+ printInfo(`Using RPC: ${rpcUrl}`);
174
+ printInfo(`Wallet: ${wallet.publicKey.toBase58()}`);
175
+
176
+ // Validate address
177
+ validatePublicKey(tokenAddress);
178
+
179
+ // Initialize SDK
180
+ const sdk = new NaraSDK({
181
+ rpcUrl,
182
+ commitment: "confirmed",
183
+ });
184
+
185
+ printInfo("Creating locker for pool with vesting parameters...");
186
+
187
+ // Create locker
188
+ const result = await createLocker(sdk, {
189
+ tokenAddress,
190
+ payer: wallet.publicKey,
191
+ });
192
+
193
+ printInfo(`Pool address: ${result.poolAddress}`);
194
+
195
+ // Handle transaction
196
+ const txResult = await handleTransaction(
197
+ sdk,
198
+ result.transaction,
199
+ [wallet],
200
+ options.exportTx || false
201
+ );
202
+
203
+ // Output result
204
+ if (options.json) {
205
+ const output = {
206
+ poolAddress: result.poolAddress,
207
+ ...(txResult.signature && { signature: txResult.signature }),
208
+ ...(txResult.base64 && { transaction: txResult.base64 }),
209
+ };
210
+ console.log(JSON.stringify(output, null, 2));
211
+ } else {
212
+ console.log(`\nPool Address: ${result.poolAddress}`);
213
+ printTransactionResult(txResult, false);
214
+
215
+ if (txResult.signature) {
216
+ printSuccess("\nLocker created successfully!");
217
+ printInfo("You can now proceed with migrating the pool.");
218
+ }
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Handle migrate check command
224
+ * @param tokenAddress Token address
225
+ * @param options Command options
226
+ */
227
+ async function handleMigrateCheck(
228
+ tokenAddress: string,
229
+ options: Omit<MigrateCheckOptions, "tokenAddress">
230
+ ): Promise<void> {
231
+ const rpcUrl = getRpcUrl(options.rpcUrl);
232
+
233
+ printInfo(`Using RPC: ${rpcUrl}`);
234
+
235
+ // Validate address
236
+ validatePublicKey(tokenAddress);
237
+
238
+ // Initialize SDK
239
+ const sdk = new NaraSDK({
240
+ rpcUrl,
241
+ commitment: "confirmed",
242
+ });
243
+
244
+ printInfo("Checking migration status...");
245
+
246
+ // Check if can migrate
247
+ const result = await canMigrate(sdk, tokenAddress);
248
+
249
+ // Output result
250
+ if (options.json) {
251
+ console.log(JSON.stringify(result, null, 2));
252
+ } else {
253
+ console.log(`\nMigration Status:`);
254
+ console.log(` Can Migrate: ${result.canMigrate ? "Yes" : "No"}`);
255
+ console.log(` Progress: ${(result.progress * 100).toFixed(2)}%`);
256
+ if (result.reason) {
257
+ console.log(` Reason: ${result.reason}`);
258
+ }
259
+
260
+ if (result.canMigrate) {
261
+ printSuccess("\nPool is ready for migration!");
262
+ printInfo("Run: nara-cli migrate launch <token-address>");
263
+ } else {
264
+ printWarning("\nPool is not ready for migration yet.");
265
+ if (result.progress < 1.0) {
266
+ printInfo(`Curve completion required: 100% (current: ${(result.progress * 100).toFixed(2)}%)`);
267
+ }
268
+ }
269
+ }
270
+ }